1 /* hp_disclib.c: HP MAC/ICD disc controller simulator library
2
3 Copyright (c) 2011-2019, J. David Bryan
4 Copyright (c) 2004-2011, Robert M. Supnik
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23 Except as contained in this notice, the names of the authors shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from the authors.
26
27 09-Dec-19 JDB Replaced debugging macros with tracing macros
28 27-Dec-18 JDB Revised fall through comments to comply with gcc 7
29 22-Apr-17 JDB A failed sim_fseek call now causes a drive fault
30 10-Oct-16 JDB Moved "hp3000_defs.h" inclusion from "hp_disclib.h"
31 03-Aug-16 JDB "fmt_bitset" now allows multiple concurrent calls
32 09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
33 08-Jun-16 JDB Corrected %d format to %u for unsigned values
34 16-May-16 JDB DRIVE_PROPS.name is now a pointer-to-constant
35 13-May-16 JDB Modified for revised SCP API function parameter types
36 03-May-16 JDB Added a trace to identify the unit requesting attention
37 24-Mar-16 JDB Changed the buffer element type from uint16 to DL_BUFFER
38 21-Mar-16 JDB Changed uint16 types to HP_WORD
39 27-Jul-15 JDB First revised release version
40 21-Feb-15 JDB Revised for new controller interface model
41 24-Dec-14 JDB Added casts for explicit downward conversions
42 27-Oct-14 JDB Corrected the relative movement calculation in start_seek
43 20-Dec-12 JDB sim_is_active() now returns t_bool
44 24-Oct-12 JDB Changed CNTLR_OPCODE to title case to avoid name clash
45 07-May-12 JDB Corrected end-of-track delay time logic
46 02-May-12 JDB First release
47 09-Nov-11 JDB Created disc controller common library from DS simulator
48
49 References:
50 - 13037 Disc Controller Technical Information Package
51 (13037-90902, August 1980)
52 - HP 13365 Integrated Controller Programming Guide
53 (13365-90901, February 1980)
54 - HP 1000 ICD/MAC Disc Diagnostic Reference Manual
55 (5955-4355, June 1984)
56 - RTE-IVB System Manager's Manual
57 (92068-90006, January 1983)
58 - DVR32 RTE Moving Head Driver Source
59 (92084-18711, Revision 5000)
60
61
62 The 13037 multiple-access disc controller (MAC) connects from one to eight HP
63 7905 (15 MB), 7906 (20 MB), 7920 (50 MB), or 7925 (120 MB) disc drives to
64 interfaces installed in from one to eight HP 1000, 2000, or 3000 CPUs. The
65 drives use a common command set and present data to the controller
66 synchronously at a data rate of 468.75 kilowords per second (2.133
67 microseconds per word).
68
69 The controller hardware consists of three PCAs: a 16-bit microprogrammed
70 processor constructed from 74S181 bit slices operating at 5 MHz, a device
71 controller that provides the interconnections to the drives and CPU
72 interfaces, and an error correction controller that enables the correction of
73 up to 32-bit error bursts. 1024 words of 24-bit firmware are stored in ROM
74 on the error correction PCA, and the execution time is 200 nanoseconds per
75 instruction.
76
77 The Integrated Controller Drive (ICD) models include the HP 7906H, 7920H, and
78 7925H. These drives are identical to the corresponding MAC drives, except
79 that they integrate a single-CPU version of the MAC controller on two PCAs
80 housed within the drive: an 8-bit microprocessor constructed from two 4-bit
81 slices operating at 3.75 MHz, and an 8-bit DMA that handles the data path
82 between the drive and CPU. Connection to the CPU is via the Hewlett-Packard
83 Interface Bus (HP-IB) -- HP's implementation of the IEEE-488 standard.
84
85 The ICD command set essentially is the MAC command set modified for
86 single-unit operation. The unit number and CPU hold bit fields in the opcode
87 words are unused in the ICD implementation. The Load TIO Register, Wakeup,
88 and Request Syndrome commands are removed, as Load TIO is used with the HP
89 3000, Wakeup is used in a multi-CPU environment, and the simpler ICD
90 controller does not support ECC. Controller status values 02B (Unit
91 Available) and 27B (Unit Unavailable) are dropped as the controller supports
92 only single units, 12B (I/O Program Error) is reused to indicate HP-IB
93 protocol errors, 13B (Sync Not Received) is added, and 17B (Possibly
94 Correctable Data Error) is removed as error correction is not supported.
95
96 Some minor redefinitions also occur. For example, status 14B (End of
97 Cylinder) is expanded to include an auto-seek beyond the drive limits, and
98 37B (Drive Attention) is restricted to just head unloads (from head loads and
99 unloads).
100
101 The MAC controller offers an HP-IB option: the HP 12745A Disc Controller to
102 HP-IB Adapter Kit. This card plugs into the 13037's chassis containing the
103 other three controller cards and connects to the CPU interface port of the
104 device controller PCA in place of the multi-CPU-interface cable. It allows
105 HP-IB 3000s and the HP 64000 Logic Development Station to connect to MAC disc
106 drives; the ICD drives are not supported on these systems.
107
108 This library provides the common functions required by HP disc controllers.
109 It implements the 13037 MAC and 13365 ICD controller command sets used with
110 the 7905/06/20/25 and 7906H/20H/25H disc drives.
111
112 The library is an adaptation of the code originally written by Bob Supnik
113 for the HP2100 DS simulator. DS simulates a 13037 controller connected via a
114 13175 disc interface to an HP 1000 computer. To create the library, the
115 functions of the controller were separated from the functions of the
116 interface. This allows the library to work with other CPU interfaces, such
117 as the 12821A HP-IB disc interface, that use substantially different
118 communication protocols. The library functions implement the controller
119 command set for the drive units. The interface functions handle the transfer
120 of commands and data to and from the CPU.
121
122 The original release of this library did not handle the data transfer between
123 the controller and the interface directly. Instead, data was moved between
124 the interface and a sector buffer by the interface simulator, and then the
125 buffer was passed to the disc library for reading or writing. This buffer
126 was also used to pass disc commands and parameters to the controller, and to
127 receive status information from the controller.
128
129 While this approach served to allow the library to be shared between
130 dissimilar interfaces, each interface had to have intimate knowledge of the
131 internal controller state in order to schedule parameter and data transfers.
132 In particular, the unit service routine had to base its actions on specific
133 controller phase and opcode pairs and manipulate the internal state variables
134 of the controller. As such, the library could not be viewed opaquely.
135
136 In addition, the HP 3000 interface required channel program support that was
137 not provided by the simulation library although it was present in hardware.
138 Adapting the existing library model would have placed an even larger and more
139 intimate burden on the interface simulation.
140
141 As a result, the library API was rewritten to model the hardware more
142 closely and provide a more strict separation of controller and interface
143 functions. Instead of providing separate routines to prepare, start, and end
144 commands, service units, and poll drives for Attention status, the new model
145 provides a single routine that represents the hardware data, flag, and
146 function buses between the interface and controller. The interface calls
147 this routine whenever the state of the flag bus changes, and the controller
148 responds by potentially changing the data and function buses. The interface
149 merely responds to those changes without requiring any other knowledge of the
150 internal state of the controller.
151
152
153 A device interface simulator interacts with the disc controller simulator via
154 the dl_controller routine, which simulates the command, status, and data
155 interconnection between the interface and controller. Utility routines are
156 also provided to attach and detach disc image files from drive units, load or
157 unload the drive's heads, set drive model and protection status, select the
158 interface timing mode (real or fast), and enable overriding of disc command
159 status returns for diagnostics.
160
161 In hardware, the interface and controller are interconnected via a 16-bit
162 bidirectional data bus (IBUS), a 6-bit flag bus and one signal (CLEAR) to
163 the controller, and a 4-bit function bus (IFNBUS) and four signals (ENID,
164 ENIR, IFVLD, and IFCLK) to the interface. The interface initiates controller
165 action by changing the state of the flag bus, and the controller responds by
166 asserting a function on the function bus. For example, the interface starts
167 a disc command by asserting CMRDY on the flag bus. The controller responds
168 by placing the IFGTC (Interface Get Command) function on the function bus and
169 asserting the ENID (Enable Interface Drivers) and IFVLD (Interface Function
170 Valid) signals. The interface then replies by placing the command on the
171 data bus, where it is read by the controller. The controller then decodes
172 the command and initiates processing.
173
174 The controller microprogram runs continuously. However, command execution
175 pauses in various wait loops whenever the controller must suspend until an
176 external event occurs. For example, an Address Record command waits first
177 for the CPU to send the cylinder address and then waits again for the CPU to
178 send the head/sector address. The controller then saves these values in
179 registers before completing the command and then waiting for the CPU to send
180 a new command.
181
182 In simulation, the dl_controller routine is called with a set of flags and
183 the content of the data bus whenever the flag state changes or a service
184 event occurs. The routine returns a set of functions and the new content of
185 the data bus. To use the above example, dl_controller would be called with
186 CMRDY and the command word and would return IFGTC; the data bus return value
187 would not be used in this case. In hardware, the controller might send a
188 series of individual functions to the interface in response to a single
189 invocation. In simulation, this series would be collected into a single
190 function set for return.
191
192 Hardware wait loops are simulated by the dl_controller routine returning to
193 the caller until the expected external event occurs. In the Address Record
194 example, dl_controller would be called first when the command is issued by
195 the CPU. The routine would initiate command processing and then return to
196 wait for the cylinder address. When the CPU provided the address, the
197 interface simulator would call dl_controller again with the cylinder value.
198 The routine would then return to wait for the head/sector address. When it
199 was available, dl_controller would be called with the value, and the routine
200 would complete the command and return to the caller to wait for a new
201 command. So, in simulation, the controller only "runs" when it has work to
202 do.
203
204 A controller instance is represented by a CNTLR_VARS structure, which
205 maintains the controller's internal state. A MAC interface will have a
206 single controller instance that controls up to eight drive units, whereas an
207 ICD interface will have one controller instance per drive unit. The minor
208 differences in controller action between the two are handled internally.
209
210 The interface simulator must declare one unit for each disc drive to be
211 controlled by the library. For a MAC controller, eight units are required,
212 plus one additional unit for the controller itself. For an ICD controller,
213 only one unit is required.
214
215 The controller maintains five values in each drive's unit structure:
216
217 u3 (CYL) -- the current drive cylinder
218 u4 (STATUS) -- the drive status (Status-2)
219 u5 (OPCODE) -- the drive current operation in process
220 u6 (PHASE) -- the drive current operation phase
221 pos -- the current byte offset into the disc image file
222
223 Drives maintain their cylinder (head positioner) locations separate from the
224 cylinder location stored in the controller. This allows the controller to
225 implement sparing by positioning to one location while storing a different
226 location in the sector headers. It also allows seek retries by issuing a
227 Recalibrate (which moves the positioner to cylinder 0) followed by the
228 original read or write (which repositioned to the cylinder stored in the
229 controller).
230
231 The drive status field contains only a subset of the status maintained by
232 drives in hardware. Specifically, the Attention, Read-Only, First Status,
233 Fault, and Seek Check bits are stored in the status field. The other bits
234 (Format Enabled, Not Ready, and Drive Busy) are set dynamically whenever
235 status is requested.
236
237 Per-drive opcode and phase values allow seeks to be overlapped. For example,
238 a Seek issued to unit 0 may be followed by a Read issued to unit 1. When the
239 seek completes on unit 0, its opcode and phase values will let the controller
240 set the appropriate seek completion status without disturbing the values
241 currently in-use by unit 1.
242
243 The simulation defines these command phases:
244
245 Idle -- the unit is not currently executing a command
246 Parameter -- the unit is obtaining or returning parameter values
247 Seek -- the unit is seeking to a new head position
248 Rotate -- the unit is rotating into position to access a sector
249 Data -- the unit is obtaining or returning sector data values
250 Intersector -- the unit is rotating between sectors
251 End -- the unit is completing a command
252
253 A value represents the current state of the unit. If a unit is active, the
254 phase will end when the unit is serviced.
255
256 In addition to the controller structure(s), an interface declares a data
257 buffer to be used for sector transfers. The buffer is an array containing
258 DL_BUFSIZE 16-bit elements; the address of the buffer is stored in the
259 controller state structure. The controller maintains the current index into
260 the buffer, as well as the length of valid data stored there. Only one
261 buffer is needed per interface, regardless of the number of controllers or
262 units handled, as a single interface cannot perform data transfers on one
263 drive concurrently with a command directed to another drive.
264
265 An interface is also responsible for declaring a structure of type
266 DELAY_PROPS that contains the timing values for the controller when in
267 FASTTIME mode. The values are event counts for these actions:
268
269 - track-to-track seek time
270 - full-stroke seek time
271 - full sector rotation time
272 - per-word data transfer time
273 - intersector gap time
274 - controller execution overhead time
275
276 These values are typically exposed via the interface's register set and so
277 may be altered by the user. A macro, DELAY_INIT, is provided to initialize
278 the structure.
279
280 An interface may optionally declare an array of DIAG_ENTRY structures if it
281 wishes to use the diagnostic override capability. Diagnostic overrides are
282 used to return controller status values that otherwise are not simulated to a
283 diagnostic program. An example would be a Correctable Data Error or a
284 Head-Sector Miscompare. If this facility is to be used, a pointer to the
285 array is placed in the CNTLR_VARS structure when it is initialized, and the
286 array itself is initialized with the DL_OVEND value that indicates that no
287 overrides are currently defined.
288
289 If the pointer is set, then when each command is started, the cylinder, head,
290 sector, and opcode values from the current override entry are checked against
291 the corresponding current controller values. If a match occurs, then the
292 controller status and Spare/Protected/Defective values are set from the entry
293 rather than being cleared, and the pointer is moved to the next entry. These
294 values will then be returned as the completion status of the current command.
295
296 If the command performs address verification, then any SPD value(s) will be
297 used as the result of the verification. In particular, setting the P bit for
298 a Write will cause a Protected Track error if the FORMAT switch is not on,
299 and any status value other than Normal Completion, Correctable Data Error, or
300 Uncorrectable Data Error will cause a verification abort.
301
302 In hardware, the errors that may occur during verification are Cylinder
303 Miscompare, Head-Sector Miscompare, Sync Timeout, Illegal Spare Access, and
304 Defective Track; any of these errors may be simulated. In addition, an
305 Uncorrectable Data Error may occur in hardware if the controller is unable to
306 verify any of the 16 sectors starting at the sector preceding the target
307 sector, but this error cannot be simulated.
308
309 Specifying either a Correctable Data Error or an Uncorrectable Data Error
310 will cause an abort at the end of the first sector of a read, write, or
311 verify command.
312
313 Correctable Data Error and Uncorrectable Data Error may also be specified for
314 the Request Syndrome command. A table entry with the former status value is
315 always followed by an additional entry that contains the values to be
316 returned for the three syndrome words and the displacement.
317
318 The last defined table entry always contains a special end-of-table value.
319
320 The controller library provides a macro, DL_MODS, that initializes MTAB
321 entries, and two utility routines, dl_set_diag and dl_show_diag, that provide
322 a user interface for setting up a table of diagnostic overrides. See the
323 comments for these routines below for the command syntax.
324
325 A macro, CNTLR_INIT, is provided to initialize the controller structure from
326 the following parameters:
327
328 - the type of the controller (MAC or ICD)
329 - the simulation DEVICE structure on which the controller operates
330 - the data buffer array
331 - the diagnostic override array or NULL if not used
332 - the structure containing the FASTTIME values
333
334 A macro, DL_REGS, is also provided that initializes a set of REG structures
335 to provide a user interface to the controller structure.
336
337 In hardware, disc drives respond to commands issued by the controller. The
338 only unsolicited status from drives occurs when the heads are loaded or
339 unloaded by the operator. In simulation, SET <dev> UNLOAD and SET <dev> LOAD
340 commands represent these actions. The controller must be notified by calling
341 the dl_load_unload routine in response to changes in a disc drive's RUN/STOP
342 switch.
343
344 Finally, the controller library provides extensive tracing of its internal
345 operations via debug logging. Six debug flags are declared for use by the
346 interface simulator. When enabled, these report controller actions at
347 various levels of detail.
348
349
350 Implementation notes:
351
352 1. The library does not simulate sector headers and trailers. Initialize
353 and Write Full Sector commands ignore the SPD bits and the supplied
354 header and trailer words. Read Full Sector fills in the header with the
355 current CHS address and sets the SPD bits to zero. The CRC and ECC words
356 in the trailer are returned as zeros. Programs that depend on drives
357 retaining the set values will fail.
358
359 2. The library does not simulate drive hold bits or support multiple CPU
360 interfaces connected to the same controller. CPU access to a valid drive
361 always succeeds.
362
363 3. The sector buffer is an array of 16-bit elements. Byte-oriented
364 interface simulators, such as the 12821A HP-IB Disc Interface, must do
365 their own byte packing and unpacking.
366
367 4. In hardware, a command pending on an interface (CMRDY asserted) while a
368 previous command is executing will be started as soon as the current
369 command completes. In simulation, dl_controller will exit when the
370 current command completes and must be called again if CMRDY is asserted.
371 This is necessary to allow the completion status of the prior command to
372 be returned to the interface before the new command is started.
373 */
374
375
376
377 #include <math.h>
378
379 #include "hp3000_defs.h" /* this must reflect the machine used */
380 #include "hp_disclib.h"
381
382
383
384 /* Program constants */
385
386 #define CNTLR_UNIT (DL_MAXDRIVE + 1) /* controller unit number */
387 #define MAX_UNIT 10 /* last legal unit number */
388
389 #define WORDS_PER_SECTOR 128 /* data words per sector */
390
391 #define UNTALK_DELAY 160 /* ICD untalk delay (constant instruction count) */
392 #define CNTLR_TIMEOUT S (1.74) /* command and parameter wait timeout (1.74 seconds) */
393
394 #define NO_EVENT -1 /* do not schedule an event */
395
396 #define NO_ACTION (CNTLR_IFN_IBUS) (NO_FUNCTIONS | NO_DATA)
397
398
399 /* Controller unit pointer */
400
401 #define CNTLR_UPTR (cvptr->device->units + cvptr->device->numunits - 1)
402
403
404 /* Unit flags accessor */
405
406 #define GET_MODEL(f) (DRIVE_TYPE) ((f) >> UNIT_MODEL_SHIFT & UNIT_MODEL_MASK)
407
408
409 /* Controller clear types */
410
411 typedef enum {
412 Hard_Clear, /* power-on/preset hard clear */
413 Timeout_Clear, /* command or parameter timeout clear */
414 Soft_Clear /* programmed soft clear */
415 } CNTLR_CLEAR;
416
417
418 /* Command accessors.
419
420 Disc commands are passed across the data bus to the controller with the CMRDY
421 flag asserted. The commands have several forms, depending on the particular
422 opcode:
423
424 15| 14 13 12| 11 10 9 | 8 7 6 | 5 4 3 | 2 1 0 HP 1000 numbering
425 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
426 | - - - | command opcode | - - - - - - - - | form 1
427 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
428 | - - - | command opcode | - - - - | unit number | form 2
429 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
430 | - - - | command opcode | H | - - - | unit number | form 3
431 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
432 | S | P | D | command opcode | H | - - - | unit number | form 4
433 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
434 | - - - | command opcode | retries | D | S | C | A | form 5
435 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
436 | - - - | command opcode | head | sector | form 6
437 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
438 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15 HP 3000 numbering
439
440 Form 1 is used by the Address Record, Clear, End, Load TIO Register, Request
441 Disc Address, and Request Syndrome commands.
442
443 Form 2 is used by the Request Disc Sector and Request Status commands.
444
445 Form 3 is used by the Read, Read Full Sector, Read With Offset, Read Without
446 Verify, Recalibrate, Seek, Verify, Wakeup, Write, and Write Full Sector
447 commands, where:
448
449 H = hold the drive
450
451 Form 4 is used by the Initialize Command, where:
452
453 S = initialize the track to spare status
454 P = initialize the track to protected status
455 D = initialize the track to defective status
456 H = hold the drive
457
458 Form 5 is used by the Set File Mask command, where:
459
460 D = decremental seek
461 S = sparing enabled
462 C = cylinder mode
463 A = auto-seek enabled
464
465 Form 6 is used by the Cold Load Read command.
466 */
467
468 #define CM_OPCODE_MASK 0017400u /* operation code mask */
469 #define CM_UNIT_MASK 0000017u /* unit number mask */
470
471 #define CM_SPARE 0100000u /* spare track */
472 #define CM_PROTECTED 0040000u /* protected track */
473 #define CM_DEFECTIVE 0020000u /* defective track */
474 #define CM_SPD_MASK (CM_SPARE | CM_PROTECTED | CM_DEFECTIVE)
475
476 #define CM_RETRY_MASK 0000360u /* retry count mask */
477 #define CM_FILE_MASK_MASK 0000017u /* file mask mask */
478
479 #define CM_DECR_SEEK 0000010u /* 0/1 = incremental/decremental seek */
480 #define CM_SPARE_EN 0000004u /* sparing enabled */
481 #define CM_CYL_MODE 0000002u /* 0/1 = surface/cylinder mode */
482 #define CM_AUTO_SEEK_EN 0000001u /* auto-seek enabled */
483
484 #define CM_HEAD_MASK 0000300u /* cold load read head mask */
485 #define CM_SECTOR_MASK 0000077u /* cold load read sector mask */
486
487
488 #define CM_OPCODE_SHIFT 8
489 #define CM_UNIT_SHIFT 0
490
491 #define CM_RETRY_SHIFT 4
492 #define CM_FILE_MASK_SHIFT 0
493
494 #define CM_HEAD_SHIFT 6
495 #define CM_SECTOR_SHIFT 0
496
497
498 #define CM_SPD(c) ((c) & CM_SPD_MASK)
499
500 #define CM_OPCODE(c) (CNTLR_OPCODE) (((c) & CM_OPCODE_MASK) >> CM_OPCODE_SHIFT)
501
502 #define CM_UNIT(c) (((c) & CM_UNIT_MASK) >> CM_UNIT_SHIFT)
503
504 #define CM_RETRY(c) (((c) & CM_RETRY_MASK) >> CM_RETRY_SHIFT)
505 #define CM_FILE_MASK(c) (((c) & CM_FILE_MASK_MASK) >> CM_FILE_MASK_SHIFT)
506
507 #define CM_HEAD(c) (((c) & CM_HEAD_MASK) >> CM_HEAD_SHIFT)
508 #define CM_SECTOR(c) (((c) & CM_SECTOR_MASK) >> CM_SECTOR_SHIFT)
509
510
511 static const BITSET_NAME file_mask_names [] = { /* File mask word */
512 "\1decremental seek\0incremental seek", /* bit 3/12 */
513 "sparing", /* bit 2/13 */
514 "\1cylinder mode\0surface mode", /* bit 1/14 */
515 "autoseek" /* bit 0/15 */
516 };
517
518 static const BITSET_FORMAT file_mask_format = /* names, offset, direction, alternates, bar */
519 { FMT_INIT (file_mask_names, 0, msb_first, has_alt, append_bar) };
520
521
522 /* Parameter accessors.
523
524 Parameters are passed across the data bus to the controller with the DTRDY
525 flag asserted. The parameters have several forms, depending on the commands
526 requesting them:
527
528 15| 14 13 12| 11 10 9 | 8 7 6 | 5 4 3 | 2 1 0 HP 1000 numbering
529 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
530 | cylinder | form 1 (in/out)
531 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
532 | 0 | head | sector | form 2 (in/out)
533 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
534 | S | P | D | status code | - - - - | unit number | form 3 (out)
535 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
536 | E | - - | drive type | - | A | R | F | L | S | K | N | B | form 4 (out)
537 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
538 | 0 | sector | form 5 (out)
539 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
540 | sector count | form 6 (in)
541 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
542 | displacement | form 7 (out)
543 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
544 | pattern | form 8 (out)
545 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
546 | data word | form 9 (in)
547 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
548 | | A | D | S | - | cyl offset magnitude | form 10 (in)
549 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
550 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15 HP 3000 numbering
551
552 Forms 1 and 2 are used by the Address Record, Request Disc Address, Request
553 Syndrome, and Seek commands.
554
555 Form 3 is used by the Request Status and Request Syndrome commands, where:
556
557 S = last track was a spare
558 P = last track was protected
559 D = last track was defective
560
561 Form 4 is used by the Request Status command, where:
562
563 E = error present
564 A = attention
565 R = read-only
566 F = format enabled
567 L = drive fault
568 S = first status
569 K = seek check
570 N = not ready
571 B = drive busy
572
573 Form 5 is used by the Request Sector Address command.
574
575 Form 6 is used by the Verify command.
576
577 Forms 7 and 8 are used by the Request Syndrome command.
578
579 Form 9 is used by the Load TIO Register command.
580
581 Form 10 is used by the Read With Offset command, where:
582
583 A = advance the clock (valid for 13037A only)
584 D = delay the clock (valid for 13037A only)
585 S = sign of cylinder offset
586 */
587
588 #define S1_SPARE 0100000u /* spare track */
589 #define S1_PROTECTED 0040000u /* protected track */
590 #define S1_DEFECTIVE 0020000u /* defective track */
591 #define S1_STATUS_MASK 0017400u /* encoded termination status mask */
592 #define S1_UNIT_MASK 0000017u /* unit number mask */
593
594 #define S1_STATUS_SHIFT 8
595 #define S1_UNIT_SHIFT 0
596
597 #define S1_STATUS(n) ((n) << S1_STATUS_SHIFT & S1_STATUS_MASK)
598 #define S1_UNIT(n) ((n) << S1_UNIT_SHIFT & S1_UNIT_MASK)
599
600
601 #define S2_ERROR 0100000u /* any error */
602 #define S2_DRIVE_TYPE_MASK 0017000u /* drive type mask */
603 #define S2_ATTENTION 0000200u /* attention */
604 #define S2_READ_ONLY 0000100u /* read-only */
605 #define S2_FORMAT_EN 0000040u /* format enabled */
606 #define S2_FAULT 0000020u /* drive fault */
607 #define S2_FIRST_STATUS 0000010u /* first status */
608 #define S2_SEEK_CHECK 0000004u /* seek check */
609 #define S2_NOT_READY 0000002u /* not ready */
610 #define S2_BUSY 0000001u /* drive busy */
611
612 #define S2_STOPS (S2_FAULT \
613 | S2_SEEK_CHECK \
614 | S2_NOT_READY) /* bits that stop drive access */
615
616 #define S2_ERRORS (S2_FAULT \
617 | S2_SEEK_CHECK \
618 | S2_NOT_READY \
619 | S2_BUSY) /* bits that set S2_ERROR */
620
621 #define S2_CPS (S2_ATTENTION \
622 | S2_FAULT \
623 | S2_FIRST_STATUS \
624 | S2_SEEK_CHECK) /* bits that are cleared by Controller Preset */
625
626 #define S2_DRIVE_TYPE_SHIFT 9
627
628 #define S2_DRIVE_TYPE(n) ((n) << S2_DRIVE_TYPE_SHIFT & S2_DRIVE_TYPE_MASK)
629 #define S2_TO_DRIVE_TYPE(n) (((n) & S2_DRIVE_TYPE_MASK) >> S2_DRIVE_TYPE_SHIFT)
630
631
632 #define PIO_HEAD_MASK 0017400u /* head mask */
633 #define PIO_SECTOR_MASK 0000377u /* sector mask */
634
635 #define PI_ADV_CLOCK 0001000u /* advance clock */
636 #define PI_DEL_CLOCK 0000400u /* delay clock */
637 #define PI_NEG_OFFSET 0000200u /* 0/1 = positive/negative cylinder offset sign */
638 #define PI_OFFSET_MASK 0000077u /* cylinder offset mask */
639
640
641 #define PIO_HEAD_SHIFT 8
642 #define PIO_SECTOR_SHIFT 0
643
644 #define PI_OFFSET_SHIFT 0
645
646
647 #define PI_HEAD(p) (((p) & PIO_HEAD_MASK) >> PIO_HEAD_SHIFT)
648 #define PI_SECTOR(p) (((p) & PIO_SECTOR_MASK) >> PIO_SECTOR_SHIFT)
649 #define PI_OFFSET(p) (((p) & PI_OFFSET_MASK) >> PI_OFFSET_SHIFT)
650
651 #define PO_HEAD(n) (((n) << PIO_HEAD_SHIFT & PIO_HEAD_MASK))
652 #define PO_SECTOR(n) (((n) << PIO_SECTOR_SHIFT & PIO_SECTOR_MASK))
653
654
655 static const BITSET_NAME status_1_names [] = { /* Status-1 word */
656 "spare", /* bit 15/0 */
657 "protected", /* bit 14/1 */
658 "defective" /* bit 13/2 */
659 };
660
661 static const BITSET_FORMAT status_1_format = /* names, offset, direction, alternates, bar */
662 { FMT_INIT (status_1_names, 13, msb_first, no_alt, append_bar) };
663
664 static const BITSET_FORMAT initialize_format = /* names, offset, direction, alternates, bar */
665 { FMT_INIT (status_1_names, 13, msb_first, no_alt, no_bar) };
666
667
668 static const BITSET_NAME status_2_names [] = { /* Status-2 word */
669 "attention", /* bit 7/ 8 */
670 "read only", /* bit 6/ 9 */
671 "format enabled", /* bit 5/10 */
672 "fault", /* bit 4/11 */
673 "first status", /* bit 3/12 */
674 "seek check", /* bit 2/13 */
675 "not ready", /* bit 1/14 */
676 "busy" /* bit 0/15 */
677 };
678
679 static const BITSET_FORMAT status_2_format = /* names, offset, direction, alternates, bar */
680 { FMT_INIT (status_2_names, 0, msb_first, no_alt, no_bar) };
681
682
683 static const BITSET_NAME offset_names [] = { /* Read With Offset parameter */
684 "advanced clock", /* bit 9/ 6 */
685 "delayed clock" /* bit 8/ 7 */
686 };
687
688 static const BITSET_FORMAT offset_format = /* names, offset, direction, alternates, bar */
689 { FMT_INIT (offset_names, 8, msb_first, no_alt, append_bar) };
690
691
692 /* Drive properties table.
693
694 In hardware, drives report their drive type numbers to the controller upon
695 receipt of a Request Status tag bus command. The drive type is used to
696 determine the legal range of head and sector addresses (the drive itself will
697 validate the cylinder address during a Seek command and the head/sector
698 address during an Address Record drive command).
699
700 In simulation, the model ID number from the unit flags is used as an index
701 into the drive properties table. The table is used to validate seek
702 parameters and to provide the mapping between CHS addresses and the linear
703 byte addresses required by the host file access routines.
704
705 The 7905/06(H) drives consist of removable and fixed platters, whereas the
706 7920(H)/25(H) drives have only removable multi-platter packs. As a result,
707 7905/06 drives are almost always accessed in platter mode, i.e., a given
708 logical disc area is fully contained on either the removable or fixed
709 platter, whereas the 7920/25 drives are almost always accessed in cylinder
710 mode with logical disc areas spanning some or all of the platters.
711
712 Disc image files are arranged as a linear set of tracks. To improve
713 locality of access, tracks in the 7905/06 images are grouped per-platter,
714 whereas tracks on the 7920 and 7925 are sequential by cylinder and head
715 number.
716
717 The simulator maps the tracks on the 7905/06 removable platter (heads 0 and
718 1) to the first half of the disc image, and the tracks on the fixed platter
719 (heads 2 and, for the 7906 only, 3) to the second half of the image. For the
720 7906(H), the cylinder-head order of the tracks is 0-0, 0-1, 1-0, 1-1, ...,
721 410-0, 410-1, 0-2, 0-3, 1-2, 1-3, ..., 410-2, 410-3. The 7905 order is the
722 same, except that head 3 tracks are omitted.
723
724 For the 7920(H)/25(H), all tracks appear in cylinder-head order, e.g., 0-0,
725 0-1, 0-2, 0-3, 0-4, 1-0, 1-1, ..., 822-2, 822-3, 822-4 for the 7920(H).
726
727 This variable-access geometry is accomplished by defining separate "heads per
728 cylinder" values for the fixed and removable sections of each drive that
729 indicates the number of heads that should be grouped for locality. The
730 removable values are set to 2 on the 7905 and 7906, indicating that those
731 drives typically use cylinders consisting of two heads. They are set to the
732 number of heads per drive for the 7920 and 7925, as those typically use
733 cylinders encompassing the entire pack.
734
735 The Drive Type is reported by the controller in the second status word
736 (Status-2) returned by the Request Status command.
737 */
738
739 typedef struct {
740 const char *name; /* drive name */
741 uint32 sectors; /* sectors per head */
742 uint32 heads; /* heads per cylinder*/
743 uint32 cylinders; /* cylinders per drive */
744 uint32 words; /* words per drive */
745 uint32 remov_heads; /* number of removable-platter heads */
746 uint32 fixed_heads; /* number of fixed-platter heads */
747 } DRIVE_PROPS;
748
749 static const DRIVE_PROPS drive_props [] = { /* indexed by DRIVE_TYPE */
750 /* drive sectors heads cylinders words remov fixed */
751 /* name per trk per cyl per drive per drive heads heads */
752 /* ------- ------- ------- ---------- ----------- ----- ----- */
753 { "7906", 48, 4, 411, WORDS_7906, 2, 2 }, /* drive type 0 */
754 { "7920", 48, 5, 823, WORDS_7920, 5, 0 }, /* drive type 1 */
755 { "7905", 48, 3, 411, WORDS_7905, 2, 1 }, /* drive type 2 */
756 { "7925", 64, 9, 823, WORDS_7925, 9, 0 } /* drive type 3 */
757 };
758
759
760 /* Delay properties table.
761
762 To support the realistic timing mode, the delay properties table contains
763 timing specifications for the supported disc drives. The times represent the
764 delays for mechanical and electronic operations. Delay values are in event
765 tick counts; macros are used to convert from times to ticks.
766
767 The drive type field differentiates between drive models available on a given
768 controller. The field is not significant for MAC and ICD controllers because
769 all of the drives supported have the same specifications.
770
771 The controller overhead values are estimates; they do not appear to be
772 documented for MAC and ICD controllers, although they are published for
773 various CS/80 drives.
774 */
775
776 static const DELAY_PROPS real_times [] = {
777 /* cntlr drive seek seek sector data intersector cntlr */
778 /* type type trk-trk full rotation per word gap overhead */
779 /* ----- -------- ------- -------- ----------- ---------- ----------- -------- */
780 { MAC, HP_All, mS (5), mS (45), uS (347.2), uS (2.13), uS (27.2), uS (200) },
781 { ICD, HP_All, mS (5), mS (45), uS (347.2), uS (2.13), uS (27.2), mS (1.5) }
782 };
783
784 #define DELAY_COUNT (sizeof real_times / sizeof real_times [0])
785
786
787 /* Estimate the current sector.
788
789 The sector currently passing under the disc heads is estimated from the
790 current "simulation time," which is the number of event ticks since the
791 simulation run was started, and the simulated disc rotation time. The
792 computation logic is:
793
794 current_sector := (simulator_time / per_sector_time) MOD sectors_per_track;
795 */
796
797 #define CURRENT_SECTOR(cvptr,uptr) \
798 (uint32) fmod (sim_gtime () / cvptr->dlyptr->sector_full, \
799 drive_props [GET_MODEL (uptr->flags)].sectors)
800
801
802 /* Command properties table.
803
804 The validity of each command for a given controller type is checked against
805 the command properties table when it is prepared for execution. The table
806 also includes the count of inbound or outbound parameters, the class of the
807 command, and flags that indicate certain common actions that are be taken.
808
809
810 Implementation notes:
811
812 1. The verify field of the Read_Without_Verify property record is set to
813 TRUE so that address verification will be done if a track boundary is
814 crossed. Initial verification is suppressed by setting the controller's
815 verify field to FALSE during initial Read_Without_Verify processing.
816 */
817
818 typedef struct {
819 uint32 param_count; /* count of input or output parameters */
820 CNTLR_CLASS classification; /* command classification */
821 t_bool valid [CNTLR_COUNT]; /* command validity, indexed by CNTLR_TYPE */
822 t_bool clear_status; /* command clears the controller status */
823 t_bool unit_field; /* command has a unit field */
824 t_bool unit_check; /* command checks the unit number validity */
825 t_bool unit_access; /* command accesses the drive unit */
826 t_bool seek_wait; /* command waits for seek completion */
827 t_bool verify_address; /* command does address verification */
828 t_bool idle_at_end; /* command idles the controller at completion */
829 uint32 preamble_size; /* size of preamble in words */
830 uint32 transfer_size; /* size of data transfer in words */
831 uint32 postamble_size; /* size of postamble in words */
832 } COMMAND_PROPERTIES;
833
834 typedef const COMMAND_PROPERTIES *PRPTR;
835
836 #define T TRUE
837 #define F FALSE
838
839 static const COMMAND_PROPERTIES cmd_props [] = {
840 /* parm opcode valid for clr unit unit unit seek addr end pre xfer post */
841 /* I/O classification MAC ICD CS80 stat fld chk acc wait verf idle size size size */
842 /* ---- -------------- --- --- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- */
843 { 0, Class_Read, { T, T, F }, T, F, T, T, F, T, F, 15, 128, 7 }, /* 00 = Cold_Load_Read */
844 { 0, Class_Control, { T, T, F }, T, T, T, T, T, F, T, 0, 0, 0 }, /* 01 = Recalibrate */
845 { 2, Class_Control, { T, T, F }, T, T, T, T, F, F, T, 0, 0, 0 }, /* 02 = Seek */
846 { 2, Class_Status, { T, T, F }, F, T, F, F, F, F, F, 0, 0, 0 }, /* 03 = Request_Status */
847 { 1, Class_Status, { T, T, F }, T, T, T, T, F, F, F, 0, 0, 0 }, /* 04 = Request_Sector_Address */
848 { 0, Class_Read, { T, T, F }, T, T, T, T, T, T, F, 15, 128, 7 }, /* 05 = Read */
849 { 0, Class_Read, { T, T, F }, T, T, T, T, T, F, F, 12, 138, 0 }, /* 06 = Read_Full_Sector */
850 { 1, Class_Read, { T, T, F }, T, T, T, T, T, T, F, 0, 0, 0 }, /* 07 = Verify */
851 { 0, Class_Write, { T, T, F }, T, T, T, T, T, T, F, 15, 128, 7 }, /* 10 = Write */
852 { 0, Class_Write, { T, T, F }, T, T, T, T, T, F, F, 12, 138, 0 }, /* 11 = Write_Full_Sector */
853 { 0, Class_Control, { T, T, F }, T, F, F, F, F, F, F, 0, 0, 0 }, /* 12 = Clear */
854 { 0, Class_Write, { T, T, F }, T, T, T, T, T, F, F, 15, 128, 7 }, /* 13 = Initialize */
855 { 2, Class_Control, { T, T, F }, T, F, F, F, F, F, F, 0, 0, 0 }, /* 14 = Address_Record */
856 { 7, Class_Status, { T, F, F }, T, F, F, F, F, F, F, 0, 0, 0 }, /* 15 = Request_Syndrome */
857 { 1, Class_Read, { T, T, F }, T, T, T, T, T, T, F, 15, 128, 7 }, /* 16 = Read_With_Offset */
858 { 0, Class_Control, { T, T, F }, T, F, F, F, F, F, F, 0, 0, 0 }, /* 17 = Set_File_Mask */
859 { 0, Class_Invalid, { F, F, F }, T, F, F, F, F, F, F, 0, 0, 0 }, /* 20 = Invalid_Opcode */
860 { 0, Class_Invalid, { F, F, F }, T, F, F, F, F, F, F, 0, 0, 0 }, /* 21 = Invalid_Opcode */
861 { 0, Class_Read, { T, T, F }, T, T, T, T, T, T, F, 15, 128, 7 }, /* 22 = Read_Without_Verify */
862 { 1, Class_Status, { T, F, F }, T, F, F, F, F, F, F, 0, 0, 0 }, /* 23 = Load_TIO_Register */
863 { 2, Class_Status, { T, T, F }, F, F, F, F, F, F, F, 0, 0, 0 }, /* 24 = Request_Disc_Address */
864 { 0, Class_Control, { T, T, F }, T, F, F, F, F, F, T, 0, 0, 0 }, /* 25 = End */
865 { 0, Class_Control, { T, F, F }, T, T, T, F, F, F, F, 0, 0, 0 } /* 26 = Wakeup */
866 };
867
868
869 /* Command functions table.
870
871 At each phase of command execution, the controller may return zero or more
872 functions for the interface to perform. The functions control the transfer
873 of parameters and data to and from the CPU. Note that commands do not
874 necessarily use all available phases.
875
876
877 Implementation notes:
878
879 1. Commands usually return BUSY and IFGTC functions to begin. However, the
880 Clear and Set File Mask commands delay the IFGTC function, which requests
881 channel service, to the End Phase to ensure that the WRTIO function
882 completes before the channel program continues. This ensures that an End
883 I/O order will pick up the correct status value from the interface.
884
885 2. Invalid commands have WRTIO in their Idle_Phase entries because the
886 diagnostic expects to see Illegal_Opcode status immediately after the SIO
887 program ends.
888 */
889
890 typedef CNTLR_IFN IFN_ARRAY [7];
891
892 static const IFN_ARRAY cmd_functions [] = { /* indexed by CNTLR_OPCODE */
893 /* 00 = Cold_Load_Read */
894 { BUSY | SRTRY | IFGTC, /* Idle Phase */
895 0, /* Parameter Phase */
896 0, /* Seek Phase */
897 0, /* Rotate Phase */
898 IFIN, /* Data Phase */
899 0, /* Intersector Phase */
900 STDFL | WRTIO | RQSRV | FREE }, /* End Phase */
901
902 /* 01 = Recalibrate */
903 { BUSY | IFGTC, /* Idle Phase */
904 0, /* Parameter Phase */
905 0, /* Seek Phase */
906 0, /* Rotate Phase */
907 0, /* Data Phase */
908 0, /* Intersector Phase */
909 WRTIO | FREE }, /* End Phase */
910
911 /* 02 = Seek */
912 { BUSY | IFGTC | STDFL, /* Idle Phase */
913 IFOUT | STDFL, /* Parameter Phase */
914 0, /* Seek Phase */
915 0, /* Rotate Phase */
916 0, /* Data Phase */
917 0, /* Intersector Phase */
918 IFOUT | WRTIO | RQSRV | FREE }, /* End Phase */
919
920 /* 03 = Request_Status */
921 { BUSY | IFGTC, /* Idle Phase */
922 IFIN | STDFL, /* Parameter Phase */
923 0, /* Seek Phase */
924 0, /* Rotate Phase */
925 0, /* Data Phase */
926 0, /* Intersector Phase */
927 WRTIO | FREE | RQSRV }, /* End Phase */
928
929 /* 04 = Request_Sector_Address */
930 { BUSY | IFGTC, /* Idle Phase */
931 IFIN | STDFL, /* Parameter Phase */
932 0, /* Seek Phase */
933 0, /* Rotate Phase */
934 0, /* Data Phase */
935 0, /* Intersector Phase */
936 WRTIO | RQSRV | FREE }, /* End Phase */
937
938 /* 05 = Read */
939 { BUSY | IFGTC, /* Idle Phase */
940 0, /* Parameter Phase */
941 0, /* Seek Phase */
942 0, /* Rotate Phase */
943 IFIN, /* Data Phase */
944 0, /* Intersector Phase */
945 STDFL | WRTIO | RQSRV | FREE }, /* End Phase */
946
947 /* 06 = Read_Full_Sector */
948 { BUSY | IFGTC, /* Idle Phase */
949 0, /* Parameter Phase */
950 0, /* Seek Phase */
951 0, /* Rotate Phase */
952 IFIN, /* Data Phase */
953 0, /* Intersector Phase */
954 STDFL | WRTIO | RQSRV | FREE }, /* End Phase */
955
956 /* 07 = Verify */
957 { BUSY | IFGTC | STDFL, /* Idle Phase */
958 IFOUT, /* Parameter Phase */
959 0, /* Seek Phase */
960 0, /* Rotate Phase */
961 0, /* Data Phase */
962 0, /* Intersector Phase */
963 STDFL | WRTIO | RQSRV | FREE }, /* End Phase */
964
965 /* 10 = Write */
966 { BUSY | IFGTC, /* Idle Phase */
967 0, /* Parameter Phase */
968 0, /* Seek Phase */
969 0, /* Rotate Phase */
970 IFOUT, /* Data Phase */
971 0, /* Intersector Phase */
972 STDFL | WRTIO | RQSRV | FREE }, /* End Phase */
973
974 /* 11 = Write_Full_Sector */
975 { BUSY | IFGTC, /* Idle Phase */
976 0, /* Parameter Phase */
977 0, /* Seek Phase */
978 0, /* Rotate Phase */
979 IFOUT, /* Data Phase */
980 0, /* Intersector Phase */
981 STDFL | WRTIO | RQSRV | FREE }, /* End Phase */
982
983 /* 12 = Clear */
984 { BUSY, /* Idle Phase */
985 0, /* Parameter Phase */
986 0, /* Seek Phase */
987 0, /* Rotate Phase */
988 0, /* Data Phase */
989 0, /* Intersector Phase */
990 IFGTC | WRTIO | STDFL | FREE }, /* End Phase */
991
992 /* 13 = Initialize */
993 { BUSY | IFGTC, /* Idle Phase */
994 0, /* Parameter Phase */
995 0, /* Seek Phase */
996 0, /* Rotate Phase */
997 IFOUT, /* Data Phase */
998 0, /* Intersector Phase */
999 STDFL | WRTIO | RQSRV | FREE }, /* End Phase */
1000
1001 /* 14 = Address_Record */
1002 { BUSY | IFGTC | STDFL, /* Idle Phase */
1003 IFOUT | STDFL, /* Parameter Phase */
1004 0, /* Seek Phase */
1005 0, /* Rotate Phase */
1006 0, /* Data Phase */
1007 0, /* Intersector Phase */
1008 IFOUT | WRTIO | RQSRV | FREE }, /* End Phase */
1009
1010 /* 15 = Request_Syndrome */
1011 { BUSY | IFGTC, /* Idle Phase */
1012 IFIN | STDFL, /* Parameter Phase */
1013 0, /* Seek Phase */
1014 0, /* Rotate Phase */
1015 0, /* Data Phase */
1016 0, /* Intersector Phase */
1017 WRTIO | RQSRV | FREE }, /* End Phase */
1018
1019 /* 16 = Read_With_Offset */
1020 { BUSY | IFGTC | STDFL, /* Idle Phase */
1021 IFOUT, /* Parameter Phase */
1022 RQSRV | STDFL, /* Seek Phase */
1023 0, /* Rotate Phase */
1024 IFIN, /* Data Phase */
1025 0, /* Intersector Phase */
1026 STDFL | WRTIO | RQSRV | FREE }, /* End Phase */
1027
1028 /* 17 = Set_File_Mask */
1029 { BUSY | SRTRY, /* Idle Phase */
1030 0, /* Parameter Phase */
1031 0, /* Seek Phase */
1032 0, /* Rotate Phase */
1033 0, /* Data Phase */
1034 0, /* Intersector Phase */
1035 IFGTC | WRTIO | STDFL | FREE }, /* End Phase */
1036
1037 /* 20 = Invalid_Opcode */
1038 { BUSY | IFGTC | WRTIO, /* Idle Phase */
1039 0, /* Parameter Phase */
1040 0, /* Seek Phase */
1041 0, /* Rotate Phase */
1042 0, /* Data Phase */
1043 0, /* Intersector Phase */
1044 FREE }, /* End Phase */
1045
1046 /* 21 = Invalid_Opcode */
1047 { BUSY | IFGTC | WRTIO, /* Idle Phase */
1048 0, /* Parameter Phase */
1049 0, /* Seek Phase */
1050 0, /* Rotate Phase */
1051 0, /* Data Phase */
1052 0, /* Intersector Phase */
1053 FREE }, /* End Phase */
1054
1055 /* 22 = Read_Without_Verify */
1056 { BUSY | IFGTC, /* Idle Phase */
1057 0, /* Parameter Phase */
1058 0, /* Seek Phase */
1059 0, /* Rotate Phase */
1060 IFIN, /* Data Phase */
1061 0, /* Intersector Phase */
1062 STDFL | WRTIO | RQSRV | FREE }, /* End Phase */
1063
1064 /* 23 = Load_TIO_Register */
1065 { BUSY | IFGTC | STDFL, /* Idle Phase */
1066 0, /* Parameter Phase */
1067 0, /* Seek Phase */
1068 0, /* Rotate Phase */
1069 0, /* Data Phase */
1070 0, /* Intersector Phase */
1071 IFOUT | WRTIO | RQSRV | FREE }, /* End Phase */
1072
1073 /* 24 = Request_Disc_Address */
1074 { BUSY | IFGTC, /* Idle Phase */
1075 IFIN | STDFL, /* Parameter Phase */
1076 0, /* Seek Phase */
1077 0, /* Rotate Phase */
1078 0, /* Data Phase */
1079 0, /* Intersector Phase */
1080 WRTIO | RQSRV | FREE }, /* End Phase */
1081
1082 /* 25 = End */
1083 { IFGTC, /* Idle Phase */
1084 0, /* Parameter Phase */
1085 0, /* Seek Phase */
1086 0, /* Rotate Phase */
1087 0, /* Data Phase */
1088 0, /* Intersector Phase */
1089 0 }, /* End Phase */
1090
1091 /* 26 = Wakeup */
1092 { BUSY | IFGTC, /* Idle Phase */
1093 0, /* Parameter Phase */
1094 0, /* Seek Phase */
1095 0, /* Rotate Phase */
1096 0, /* Data Phase */
1097 0, /* Intersector Phase */
1098 WRTIO | STDFL | FREE } /* End Phase */
1099 };
1100
1101
1102 /* Status functions table.
1103
1104 The End Phase functions above are proper for commands that complete normally.
1105 Commands that return an error status return additional functions that depend
1106 on the particular status code. An entry in this table is ORed with the End
1107 Phase function to produce the final function set that is returned to the
1108 interface.
1109 */
1110
1111 static const CNTLR_IFN status_functions [] = { /* indexed by CNTLR_STATUS */
1112 0, /* 000 = Normal Completion */
1113 STINT | WRTIO | FREE, /* 001 = Illegal Opcode */
1114 STDFL | WRTIO | FREE, /* 002 = Unit Available */
1115 STINT | WRTIO | FREE, /* 003 = Illegal Drive Type */
1116 0, /* 004 = (undefined) */
1117 0, /* 005 = (undefined) */
1118 0, /* 006 = (undefined) */
1119 STINT | WRTIO | FREE, /* 007 = Cylinder Miscompare */
1120 DVEND | RQSRV | WRTIO | FREE, /* 010 = Uncorrectable Data Error */
1121 STINT | WRTIO | FREE, /* 011 = Head-Sector Miscompare */
1122 STINT | WRTIO | FREE, /* 012 = I/O Program Error */
1123 DVEND | RQSRV | WRTIO | FREE, /* 013 = Sync Timeout */
1124 STINT | WRTIO | FREE, /* 014 = End of Cylinder */
1125 0, /* 015 = (undefined) */
1126 DVEND | RQSRV | WRTIO | FREE, /* 016 = Data Overrun */
1127 DVEND | RQSRV | WRTIO | FREE, /* 017 = Correctable Data Error */
1128 STINT | WRTIO | FREE, /* 020 = Illegal Spare Access */
1129 STINT | WRTIO | FREE, /* 021 = Defective Track */
1130 STINT | WRTIO | FREE, /* 022 = Access Not Ready */
1131 STINT | WRTIO | FREE, /* 023 = Status-2 Error */
1132 0, /* 024 = (undefined) */
1133 0, /* 025 = (undefined) */
1134 STINT | WRTIO | FREE, /* 026 = Protected Track */
1135 STINT | WRTIO | FREE, /* 027 = Unit Unavailable */
1136 0, /* 030 = (undefined) */
1137 0, /* 031 = (undefined) */
1138 0, /* 032 = (undefined) */
1139 0, /* 033 = (undefined) */
1140 0, /* 034 = (undefined) */
1141 0, /* 035 = (undefined) */
1142 0, /* 036 = (undefined) */
1143 STINT | WRTIO | FREE /* 037 = Drive Attention */
1144 };
1145
1146
1147 /* Controller operation names */
1148
1149 static const BITSET_NAME flag_names [] = { /* controller flag names, in CNTLR_FLAG order */
1150 "CLEAR", /* 000001 */
1151 "CMRDY", /* 000002 */
1152 "DTRDY", /* 000004 */
1153 "EOD", /* 000010 */
1154 "INTOK", /* 000020 */
1155 "OVRUN", /* 000040 */
1156 "XFRNG" /* 000100 */
1157 };
1158
1159 static const BITSET_FORMAT flag_format = /* names, offset, direction, alternates, bar */
1160 { FMT_INIT (flag_names, 0, lsb_first, no_alt, no_bar) };
1161
1162
1163 static const BITSET_NAME function_names [] = { /* interface function names, in CNTLR_IFN order */
1164 "BUSY", /* 000000200000 */
1165 "DSCIF", /* 000000400000 */
1166 "SELIF", /* 000001000000 */
1167 "IFIN", /* 000002000000 */
1168 "IFOUT", /* 000004000000 */
1169 "IFGTC", /* 000010000000 */
1170 "IFPRF", /* 000020000000 */
1171 "RQSRV", /* 000040000000 */
1172 "DVEND", /* 000100000000 */
1173 "SRTRY", /* 000200000000 */
1174 "STDFL", /* 000400000000 */
1175 "STINT", /* 001000000000 */
1176 "WRTIO", /* 002000000000 */
1177 "FREE" /* 004000000000 */
1178 };
1179
1180 static const BITSET_FORMAT function_format = /* names, offset, direction, alternates, bar */
1181 { FMT_INIT (function_names, 16, lsb_first, no_alt, no_bar) };
1182
1183
1184 static const char invalid_name [] = "Invalid";
1185
1186 static const char *opcode_name [] = { /* command opcode names, in CNTLR_OPCODE order */
1187 "Cold Load Read", /* 00 */
1188 "Recalibrate", /* 01 */
1189 "Seek", /* 02 */
1190 "Request Status", /* 03 */
1191 "Request Sector Address", /* 04 */
1192 "Read", /* 05 */
1193 "Read Full Sector", /* 06 */
1194 "Verify", /* 07 */
1195 "Write", /* 10 */
1196 "Write Full Sector", /* 11 */
1197 "Clear", /* 12 */
1198 "Initialize", /* 13 */
1199 "Address Record", /* 14 */
1200 "Request Syndrome", /* 15 */
1201 "Read With Offset", /* 16 */
1202 "Set File Mask", /* 17 */
1203 invalid_name, /* 20 = invalid */
1204 invalid_name, /* 21 = invalid */
1205 "Read Without Verify", /* 22 */
1206 "Load TIO Register", /* 23 */
1207 "Request Disc Address", /* 24 */
1208 "End", /* 25 */
1209 "Wakeup" /* 26 */
1210 };
1211
1212 #define OPCODE_LENGTH 22 /* length of the longest opcode name */
1213
1214
1215 static const char *const status_name [] = { /* command status names, in CNTLR_STATUS order */
1216 "Normal Completion", /* 000 */
1217 "Illegal Opcode", /* 001 */
1218 "Unit Available", /* 002 */
1219 "Illegal Drive Type", /* 003 */
1220 NULL, /* 004 */
1221 NULL, /* 005 */
1222 NULL, /* 006 */
1223 "Cylinder Miscompare", /* 007 */
1224 "Uncorrectable Data Error", /* 010 */
1225 "Head-Sector Miscompare", /* 011 */
1226 "I/O Program Error", /* 012 */
1227 "Sync Timeout", /* 013 */
1228 "End of Cylinder", /* 014 */
1229 NULL, /* 015 */
1230 "Data Overrun", /* 016 */
1231 "Correctable Data Error", /* 017 */
1232 "Illegal Spare Access", /* 020 */
1233 "Defective Track", /* 021 */
1234 "Access Not Ready", /* 022 */
1235 "Status-2 Error", /* 023 */
1236 NULL, /* 024 */
1237 NULL, /* 025 */
1238 "Protected Track", /* 026 */
1239 "Unit Unavailable", /* 027 */
1240 NULL, /* 030 */
1241 NULL, /* 031 */
1242 NULL, /* 032 */
1243 NULL, /* 033 */
1244 NULL, /* 034 */
1245 NULL, /* 035 */
1246 NULL, /* 036 */
1247 "Drive Attention" /* 037 */
1248 };
1249
1250 #define STATUS_LENGTH 24 /* length of the longest status name */
1251
1252
1253 static const char *state_name [] = { /* controller state names, in CNTLR_STATE order */
1254 "idle",
1255 "wait",
1256 "busy"
1257 };
1258
1259
1260 static const char *phase_name [] = { /* unit state names, in CNTLR_PHASE order */
1261 "idle",
1262 "parameter",
1263 "seek",
1264 "rotate",
1265 "data",
1266 "intersector",
1267 "end"
1268 };
1269
1270
1271 /* Disc library local controller routines */
1272
1273 static CNTLR_IFN_IBUS start_command (CVPTR cvptr, CNTLR_FLAG_SET flags, CNTLR_IBUS data);
1274 static CNTLR_IFN_IBUS continue_command (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags, CNTLR_IBUS data);
1275 static CNTLR_IFN_IBUS poll_drives (CVPTR cvptr);
1276
1277 static void end_command (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status);
1278 static t_bool start_seek (CVPTR cvptr, UNIT *uptr);
1279 static t_bool start_read (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags);
1280 static void end_read (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags);
1281 static t_bool start_write (CVPTR cvptr, UNIT *uptr);
1282 static void end_write (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags);
1283 static t_bool position_sector (CVPTR cvptr, UNIT *uptr);
1284 static void next_sector (CVPTR cvptr, UNIT *uptr);
1285 static void io_error (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status);
1286 static void set_completion (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status);
1287 static void clear_controller (CVPTR cvptr, CNTLR_CLEAR clear_type);
1288 static void idle_controller (CVPTR cvptr);
1289
1290 /* Disc library local utility routines */
1291
1292 static void set_address (CVPTR cvptr, uint32 index);
1293 static void wait_timer (CVPTR cvptr, FLIP_FLOP action);
1294 static HP_WORD drive_status (UNIT *uptr);
1295 static t_stat activate_unit (CVPTR cvptr, UNIT *uptr);
1296 static void set_rotation (CVPTR cvptr, UNIT *uptr);
1297 static void set_file_pos (CVPTR cvptr, UNIT *uptr, uint32 model);
1298
1299
1300
1301 /* Disc library global controller routines */
1302
1303
1304 /* Disc controller interface.
1305
1306 This routine simulates the hardware interconnection between the disc
1307 controller and the CPU interface. This routine is called whenever the flag
1308 state changes. This would be when a new command is to be started, when
1309 command parameters are supplied or status words are retrieved, and when
1310 sector data is read or written. It must also be called when the unit service
1311 routine is entered. The caller passes in the set of interface flags and the
1312 contents of the data buffer. The routine returns a set of functions and, if
1313 IFIN is included in set, the new content of the data buffer.
1314
1315 In hardware, the controller microcode executes in one of three states:
1316
1317 1. In the Poll Loop, which looks for commands and drive attention requests.
1318
1319 In each pass of the loop, the next CPU interface in turn is selected and
1320 checked for a command; if present, it is executed. If not, the
1321 interface is disconnected, and then all drives are checked in turn until
1322 one is found with Attention status; if none are found, the loop
1323 continues. If a drive is requesting attention, the associated CPU
1324 interface is selected to check for a command; if present, it is executed.
1325 If not, and the interface allows interrupts, an interrupt request is made
1326 and the Command Wait Loop is entered. If interrupts are not allowed, the
1327 interface is disconnected, and the Poll Loop continues.
1328
1329 2. In the Command Wait Loop, which looks for commands.
1330
1331 In each pass of the loop, the currently selected CPU interface is checked
1332 for a command; if present, it is executed. If not, the Command Wait Loop
1333 continues. While in the loop, a 1.74 second timer is running. If it
1334 expires before a command is received, the file mask is reset, the current
1335 interface is disconnected, and the Poll Loop is entered.
1336
1337 3. In command execution, which processes the current command.
1338
1339 While a command is executing, any waits for input parameters, seek
1340 completion, data transfers, or output status words are handled
1341 internally. Each wait is governed by the 1.74 second timer; if it
1342 expires, the command is aborted, the file mask is reset, the current
1343 interface is disconnected, and the Poll Loop is reentered.
1344
1345 In simulation, these states are represented by the CNTLR_STATE values
1346 Idle_State, Wait_State, and Busy_State, respectively.
1347
1348 A MAC controller operates from one to eight drives, represented by an array
1349 of one to eight UNITs. The unit number present in the command is used to
1350 index to the target unit via the "units" pointer in the DEVICE structure.
1351 One additional unit that represents the controller is required, separate from
1352 the individual drive units. Commands that do not access the drive, such as
1353 Address Record, are scheduled on the controller unit to allow controller
1354 commands to execute while drive units are seeking. The command wait timer is
1355 also scheduled on the controller unit to limit the amount of time the
1356 controller will wait for the interface to supply a command or parameter.
1357
1358 An ICD simulation manages a single unit corresponding to the drive in which
1359 the controller is integrated. A device interface declares a UNIT array
1360 corresponding to the number of drives supported and passes the unit number to
1361 use during controller initialization. A controller unit is not used, as all
1362 commands are scheduled on the drive unit associated with a given controller.
1363
1364 On entry, the flags and controller state are examined to determine if a new
1365 controller command should be initiated or the current command should be
1366 continued. If this routine is being called as a result of an event service,
1367 "uptr" will point at the unit being serviced. Otherwise, "uptr" will be NULL
1368 (for example, when starting a new controller command).
1369
1370 If the CLEARF flag is asserted, then perform a hard clear on the controller.
1371 Otherwise, if a 3000 channel error has occurred, then terminate any command
1372 in progress and return I/O Program Error status. Otherwise, if the
1373 controller is currently busy with a command, or if this is an event service
1374 entry, then process the next step of the command. Otherwise, if the CMRDY
1375 flag is asserted, then start a new command. If none of these cases pertain,
1376 or if the controller is now idle, poll the drives for attention.
1377
1378 In all cases, return a combined function set and outbound data word to the
1379 caller.
1380
1381
1382 Implementation notes:
1383
1384 1. This routine will be entered when the drive unit event service occurs
1385 for seek completion, and Seek_Phase processing in continue_command will
1386 set the drive's Attention bit. The drives must then be polled and the
1387 return functions and TIO value set to generate a CPU interrupt.
1388
1389 A seek command started on one drive while a second drive already has its
1390 Attention bit set would seem to overwrite the first drive's Seek
1391 completion status with the second drive's Attention status. However,
1392 this won't occur because INTOK will not be set until the first drive's
1393 channel program completes, and so the drive poll is inhibited until then.
1394 */
1395
dl_controller(CVPTR cvptr,UNIT * uptr,CNTLR_FLAG_SET flags,CNTLR_IBUS data)1396 CNTLR_IFN_IBUS dl_controller (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags, CNTLR_IBUS data)
1397 {
1398 CNTLR_IFN_IBUS outbound;
1399
1400 tpprintf (cvptr->device, DL_DEB_IOB, "Controller (%s) received data %06o with flags %s\n",
1401 state_name [cvptr->state], data, fmt_bitset (flags, flag_format));
1402
1403 if (flags & CLEARF) { /* if the CLEAR flag is asserted */
1404 clear_controller (cvptr, Hard_Clear); /* then perform a hard clear on the controller */
1405 outbound = NO_ACTION; /* and take no other action on return */
1406
1407 tpprintf (cvptr->device, DL_DEB_CMD, "Hard clear\n");
1408 }
1409
1410 else if (flags & XFRNG) { /* otherwise if a channel error has occurred */
1411 end_command (cvptr, uptr, IO_Program_Error); /* then terminate the command with error status */
1412 cvptr->spd_unit = 0; /* and clear the SPD and unit parts of the status */
1413
1414 outbound = status_functions [IO_Program_Error] /* set the Status-1 value for WRTIO */
1415 | S1_STATUS (IO_Program_Error);
1416 }
1417
1418 else if (uptr || cvptr->state == Busy_State) /* otherwise if a command is in process */
1419 outbound = continue_command (cvptr, uptr, flags, data); /* then continue with command processing */
1420
1421 else if (flags & CMRDY) /* otherwise if a new command is ready */
1422 outbound = start_command (cvptr, flags, data); /* then begin command execution */
1423
1424 else /* otherwise there's nothing to do */
1425 outbound = NO_ACTION; /* except possibly poll for attention */
1426
1427 if (cvptr->state == Idle_State /* if the controller is idle */
1428 && cvptr->type == MAC /* and it's a MAC controller */
1429 && flags & INTOK) /* and interrupts are allowed */
1430 outbound = poll_drives (cvptr); /* then poll the drives for attention */
1431
1432 tpprintf (cvptr->device, DL_DEB_IOB, "Controller (%s) returned data %06o with functions %s\n",
1433 state_name [cvptr->state], DLIBUS (outbound),
1434 fmt_bitset (DLIFN (outbound), function_format));
1435
1436 return outbound;
1437 }
1438
1439
1440 /* Start a new command.
1441
1442 This routine simulates the controller microcode entry into the command
1443 executor corresponding to the command presented by the CPU interface. It's
1444 called when the controller is waiting for a command and the interface asserts
1445 CMRDY to indicate that a new command is available. It returns a set of
1446 action functions and a data word to the caller. For a good command, it also
1447 sets up the next phase of operation on the controller and/or drive unit and
1448 schedules the unit(s) as appropriate.
1449
1450 On entry, the command word is supplied in the "inbound_data" parameter; this
1451 simulates the microcode issuing an IFPRF (Interface Prefetch) to obtain the
1452 command. The opcode is isolated from the command word and checked for
1453 validity. If it's OK, it's used as an index into the command properties
1454 table. If the command contains a unit number field, it is extracted, checked
1455 for validity, and used to derive a pointer to the corresponding UNIT
1456 structure. If the command does not access the drive, or if the unit number
1457 is invalid, the unit pointer is set to NULL. A pointer to the controller
1458 unit is also set up; for ICD controllers, the controller and drive unit are
1459 the same.
1460
1461 The controller library supports up to eight drives per MAC controller and one
1462 drive per ICD controller. Unit numbers 0-7 represent valid drive addresses
1463 for a MAC controller. The unit number field is ignored for an ICD
1464 controller, and unit 0 is always implied. In simulation, MAC unit numbers
1465 correspond one-for-one with device units, whereas one ICD controller is
1466 associated with each of the several device units that are independently
1467 addressed as unit 0.
1468
1469 The MAC controller firmware allows access to unit numbers 8-10 without
1470 causing a Unit Unavailable error. Instead, the controller reports these
1471 legal-but-invalid units as permanently offline.
1472
1473 If a diagnostic override is defined, and the cylinder, head, sector, and
1474 opcode values from the current override entry match their corresponding
1475 controller values, then the status and SPD values are set from the entry
1476 rather than being cleared, and the pointer is moved to the next entry. The
1477 controller is then set to the busy state, and the validity of the opcode and
1478 unit are checked. If any errors are detected, the appropriate status is set,
1479 and the controller unit is scheduled for the End_Phase to simulate the
1480 controller processing overhead.
1481
1482 If the command and unit are valid, then if the command accesses a drive unit,
1483 the unit's OPCODE field is set, and any pending Attention status is cleared.
1484 If the command takes or returns parameters, then the Parameter_Phase is set
1485 up on the controller unit and the wait timer is started. Commands that
1486 return parameters temporarily store their parameter values in the sector
1487 buffer at this time for return as the CPU interface requests them. The Cold
1488 Load Read and Recalibrate commands start their respective seeks at this time,
1489 and commands that complete immediately, e.g., Set File Mask, Wakeup, etc.,
1490 schedule the End_Phase on the controller unit and set up the status value for
1491 return if they end with the WRTIO function.
1492
1493 Finally, the controller and/or drive units are activated if they were
1494 scheduled. If a seek is in progress on a drive when a command that
1495 waits for seek completion is started, the unit is not rescheduled. Instead,
1496 the unit is left in the Seek_Phase, but the unit's OPCODE field is changed to
1497 reflect the new command so that the command will start automatically when the
1498 seek completes.
1499
1500
1501 Implementation notes:
1502
1503 1. A command is started only if the controller is not busy. Therefore, the
1504 target unit can be only in either the Seek_Phase or the Idle_Phase, as
1505 all other phases will have the controller in the Busy_State.
1506
1507 2. Commands that access units and take parameters (e.g., Verify) set up the
1508 parameter access on the controller unit but perform the rest of the
1509 operation on the drive unit. The controller must be used so that
1510 parameters may be read for the next command for a unit that is currently
1511 seeking (stacked commands wait for seek completion after parameters have
1512 been read).
1513
1514 3. Drive Attention may be still set on a drive that has completed a seek but
1515 has not been able to interrupt the CPU before a new command is started.
1516 Therefore, Attention is always cleared when a command starts.
1517
1518 4. In hardware, the Recalibrate command waits for a seek-in-progress to
1519 complete before the RCL tag is sent to the drive. In simulation,
1520 repositioning the heads to cylinder 0 is started immediately, but any
1521 remaining time from a seek-in-progress is added to the time required for
1522 repositioning. The effect is that recalibration completes in the time it
1523 would have taken for the seek-in-progress to complete followed by
1524 repositioning from that location.
1525
1526 5. The Cold Load Read command does not check for Access Not Ready before
1527 issuing the seek to cylinder 0, so if a seek or recalibrate is in
1528 progress, the drive will reject it with a Seek Check error. However, the
1529 command continues, and when the seek in progress completes and the read
1530 begins, the Seek Check error will abort the command at this point with a
1531 Status-2 Error.
1532
1533 6. ECC is not simulated, so the Request Syndrome command always returns zero
1534 values for the displacement and patterns and Uncorrectable Data Error for
1535 the status. Correctable Data Error status cannot occur unless a
1536 diagnostic override is in effect.
1537
1538 7. The Wakeup command references a drive unit but is scheduled on the
1539 controller unit because it may be issued while the drive is seeking.
1540 */
1541
start_command(CVPTR cvptr,CNTLR_FLAG_SET inbound_flags,CNTLR_IBUS inbound_data)1542 static CNTLR_IFN_IBUS start_command (CVPTR cvptr, CNTLR_FLAG_SET inbound_flags, CNTLR_IBUS inbound_data)
1543 {
1544 UNIT *cuptr, *duptr, *rptr;
1545 uint32 unit;
1546 int32 seek_wait_time;
1547 PRPTR props;
1548 CNTLR_IFN_IBUS outbound;
1549 DIAG_ENTRY *dop = NULL;
1550
1551 wait_timer (cvptr, CLEAR); /* stop the command wait timer */
1552
1553 cvptr->opcode = CM_OPCODE (inbound_data); /* get the opcode from the command */
1554
1555 if (cvptr->opcode > LAST_OPCODE /* if the opcode is undefined */
1556 || cvptr->type > LAST_CNTLR /* or the controller type is undefined */
1557 || cmd_props [cvptr->opcode].valid [cvptr->type] == FALSE) /* or the opcode is not valid for this controller */
1558 cvptr->opcode = Invalid_Opcode; /* then replace it with the invalid opcode */
1559
1560 props = &cmd_props [cvptr->opcode]; /* get the properties associated with the opcode */
1561
1562 if (cvptr->type == MAC) { /* if this a MAC controller */
1563 if (props->unit_field) /* then if the unit field is defined */
1564 unit = CM_UNIT (inbound_data); /* then get it from the command */
1565 else /* otherwise the unit is not specified in the command */
1566 unit = 0; /* so the unit is always unit 0 */
1567
1568 cuptr = CNTLR_UPTR; /* set the controller unit pointer */
1569
1570 if (unit > DL_MAXDRIVE /* if the unit number is invalid */
1571 || props->unit_access == FALSE) /* or the command accesses the controller only */
1572 duptr = NULL; /* then the drive pointer does not correspond to a unit */
1573 else /* otherwise the command accesses a valid drive unit */
1574 duptr = cvptr->device->units + unit; /* so set the drive pointer to the unit */
1575 }
1576
1577 else { /* otherwise this is an ICD or CS/80 controller */
1578 unit = 0; /* so the unit value isn't used */
1579 cuptr = duptr = /* and the unit number was predefined */
1580 cvptr->device->units + cvptr->poll_unit; /* when the controller structure was initialized */
1581 }
1582
1583 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command started\n",
1584 unit, opcode_name [cvptr->opcode]);
1585
1586 if (cvptr->dop_index >= 0) /* if the diagnostic override table is defined */
1587 dop = cvptr->dop_base + cvptr->dop_index; /* then point at the current entry */
1588
1589 if (dop /* if the table entry exists */
1590 && dop->cylinder == cvptr->cylinder /* and the cylinder, */
1591 && dop->head == cvptr->head /* head, */
1592 && dop->sector == cvptr->sector /* sector, */
1593 && dop->opcode == cvptr->opcode) { /* and opcode values match the current values */
1594 cvptr->spd_unit = dop->spd | unit; /* then override the Spare/Protected/Defective */
1595 cvptr->status = dop->status; /* and status values from the override entry */
1596
1597 cvptr->dop_index++; /* point at the */
1598 dop++; /* next table entry */
1599
1600 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u cylinder %u head %u sector %u diagnostic override\n",
1601 unit, cvptr->cylinder, cvptr->head, cvptr->sector);
1602 }
1603
1604 else if (props->clear_status) { /* otherwise if this command clears prior status */
1605 cvptr->status = Normal_Completion; /* then do it */
1606 cvptr->spd_unit = unit; /* and save the unit number for status requests */
1607 }
1608
1609
1610 cvptr->state = Busy_State; /* the controller is now busy */
1611 cvptr->index = 0; /* reset the buffer index */
1612 cvptr->count = 0; /* and the sector/word count */
1613 cvptr->verify = props->verify_address; /* set the address verification flag */
1614
1615 cuptr->OPCODE = cvptr->opcode; /* set the controller unit opcode */
1616 cuptr->wait = NO_EVENT; /* and assume no controller scheduling */
1617
1618 outbound = cmd_functions [cvptr->opcode] [Idle_Phase]; /* set up the initial function set and zero data */
1619
1620
1621 if (cvptr->opcode == Invalid_Opcode) /* if the opcode is invalid */
1622 set_completion (cvptr, cuptr, Illegal_Opcode); /* then finish with an illegal opcode error */
1623
1624 else if (props->unit_check && unit > MAX_UNIT) /* otherwise if the unit number is checked and is illegal */
1625 set_completion (cvptr, cuptr, Unit_Unavailable); /* then finish with a unit unavailable error */
1626
1627 else if (props->unit_check && unit > DL_MAXDRIVE /* otherwise if the unit number is checked and is invalid */
1628 || props->seek_wait && (drive_status (duptr) & S2_STOPS)) /* or if we're waiting for an offline drive */
1629 set_completion (cvptr, cuptr, Status_2_Error); /* then finish with a Status-2 error */
1630
1631 else { /* otherwise the command and unit are valid */
1632 if (duptr) { /* if the drive unit is accessed */
1633 duptr->OPCODE = cvptr->opcode; /* then set the drive opcode for later reference */
1634 duptr->wait = NO_EVENT; /* assume no drive scheduling */
1635 duptr->STATUS &= ~S2_ATTENTION; /* clear any pending Attention status */
1636 }
1637
1638 if (props->param_count != 0) { /* if the command takes or returns parameters */
1639 cvptr->length = props->param_count; /* then set the parameter count */
1640 cuptr->PHASE = Parameter_Phase; /* set up the parameter transfer on the controller */
1641 wait_timer (cvptr, SET); /* and start the timer to wait for the first parameter */
1642 }
1643
1644 switch (cvptr->opcode) { /* dispatch the command for initiation */
1645
1646 case Cold_Load_Read:
1647 cvptr->cylinder = 0; /* set the cylinder address to 0 */
1648 cvptr->head = CM_HEAD (inbound_data); /* set the head and */
1649 cvptr->sector = CM_SECTOR (inbound_data); /* sector addresses from the command */
1650
1651 if (start_seek (cvptr, duptr) == FALSE) /* start the seek; if it failed */
1652 set_completion (cvptr, cuptr, Status_2_Error); /* then set up the completion status */
1653
1654 tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s from cylinder %u head %u sector %u\n",
1655 unit, opcode_name [Cold_Load_Read], cvptr->cylinder, cvptr->head, cvptr->sector);
1656 break; /* wait for seek completion */
1657
1658
1659 case Recalibrate:
1660 tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s to cylinder 0\n",
1661 unit, opcode_name [Recalibrate]);
1662
1663 if (duptr->PHASE == Seek_Phase) { /* if the unit is currently seeking */
1664 seek_wait_time = sim_activate_time (duptr); /* then get the remaining event time */
1665
1666 sim_cancel (duptr); /* cancel the event to allow rescheduling */
1667 duptr->PHASE = Idle_Phase; /* and idle the drive so that the seek succeeds */
1668
1669 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command waiting for seek completion\n",
1670 unit, opcode_name [Recalibrate]);
1671 }
1672
1673 else /* otherwise the drive is idle */
1674 seek_wait_time = 0; /* so there's no seek wait time */
1675
1676 if (start_seek (cvptr, duptr) == FALSE) /* start the seek; if it failed */
1677 set_completion (cvptr, cuptr, Status_2_Error); /* then set up the completion status */
1678
1679 else if (cvptr->type == MAC) /* otherwise if this a MAC controller */
1680 set_completion (cvptr, cuptr, Normal_Completion); /* then schedule seek completion */
1681
1682 duptr->wait = duptr->wait + seek_wait_time; /* increase the delay by any remaining seek time */
1683 break; /* and wait for the recalibrate to complete */
1684
1685
1686 case Request_Status:
1687 cvptr->buffer [0] = (DL_BUFFER) (cvptr->spd_unit /* set the Status-1 value */
1688 | S1_STATUS (cvptr->status)); /* into the buffer */
1689
1690 if (cvptr->type == MAC) /* if this a MAC controller */
1691 if (unit > DL_MAXDRIVE) /* then if the unit number is invalid */
1692 rptr = NULL; /* then it does not correspond to a unit */
1693 else /* otherwise the unit is valid */
1694 rptr = cvptr->device->units + unit; /* so get the address of the referenced unit */
1695 else /* otherwise it is not a MAC controller */
1696 rptr = duptr; /* so the referenced unit is the current unit */
1697
1698 cvptr->buffer [1] = (DL_BUFFER) drive_status (rptr); /* set the Status-2 value into the buffer */
1699
1700 tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s returns %sunit %u | %s and %s%s | %s\n",
1701 unit, opcode_name [Request_Status],
1702 fmt_bitset (cvptr->spd_unit, status_1_format),
1703 CM_UNIT (cvptr->spd_unit), dl_status_name (cvptr->status),
1704 (cvptr->buffer [1] & S2_ERROR ? "error | " : ""),
1705 drive_props [S2_TO_DRIVE_TYPE (cvptr->buffer [1])].name,
1706 fmt_bitset (cvptr->buffer [1], status_2_format));
1707
1708 if (rptr) /* if the referenced unit is valid */
1709 rptr->STATUS &= ~S2_FIRST_STATUS; /* then clear the First Status bit */
1710
1711 cvptr->spd_unit = S1_UNIT (unit); /* save the unit number referenced in the command */
1712
1713 if (unit > MAX_UNIT) /* if the unit number is illegal */
1714 cvptr->status = Unit_Unavailable; /* then the next status will be Unit Unavailable */
1715 else /* otherwise a legal unit */
1716 cvptr->status = Normal_Completion; /* clears the controller status */
1717 break;
1718
1719
1720 case Request_Sector_Address:
1721 if (drive_status (duptr) & S2_NOT_READY) /* if the drive is not ready */
1722 set_completion (cvptr, cuptr, Status_2_Error); /* then finish with Not Ready status */
1723
1724 else /* otherwise the drive is ready */
1725 cvptr->buffer [0] = /* so calculate the current sector address */
1726 (DL_BUFFER) CURRENT_SECTOR (cvptr, duptr);
1727
1728 tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s returns sector %u\n",
1729 unit, opcode_name [Request_Sector_Address], cvptr->buffer [0]);
1730 break;
1731
1732
1733 case Clear:
1734 clear_controller (cvptr, Soft_Clear); /* clear the controller */
1735 set_completion (cvptr, cuptr, Normal_Completion); /* and schedule the command completion */
1736
1737 tpprintf (cvptr->device, DL_DEB_CMD, "%s\n", opcode_name [Clear]);
1738 break;
1739
1740
1741 case Request_Syndrome:
1742 if (cvptr->status == Correctable_Data_Error) { /* if this is a correction override */
1743 cvptr->buffer [3] = (DL_BUFFER) dop->spd; /* then load the displacement */
1744 cvptr->buffer [4] = (DL_BUFFER) dop->cylinder; /* and three */
1745 cvptr->buffer [5] = (DL_BUFFER) dop->head; /* syndrome words */
1746 cvptr->buffer [6] = (DL_BUFFER) dop->sector; /* from the override entry */
1747
1748 cvptr->dop_index++; /* point at the */
1749 dop++; /* next table entry */
1750 }
1751
1752 else { /* otherwise no correction data was supplied */
1753 cvptr->buffer [3] = 0; /* so the displacement is always zero */
1754 cvptr->buffer [4] = 0; /* as are */
1755 cvptr->buffer [5] = 0; /* the three */
1756 cvptr->buffer [6] = 0; /* syndrome words */
1757
1758 if (cvptr->status == Normal_Completion) /* if we've been called without an override */
1759 cvptr->status = Uncorrectable_Data_Error; /* then presume that an uncorrectable error occurred */
1760 }
1761
1762 cvptr->buffer [0] = (DL_BUFFER) (cvptr->spd_unit /* save the Status-1 value */
1763 | S1_STATUS (cvptr->status)); /* in the buffer */
1764
1765 set_address (cvptr, 1); /* save the CHS values in the buffer */
1766
1767 tpprintf (cvptr->device, DL_DEB_CMD, "%s returns %sunit %u | %s | cylinder %u head %u sector %u | "
1768 "syndrome %06o %06o %06o %06o\n",
1769 opcode_name [Request_Syndrome], fmt_bitset (cvptr->spd_unit, status_1_format),
1770 CM_UNIT (cvptr->spd_unit), dl_status_name (cvptr->status),
1771 cvptr->cylinder, cvptr->head, cvptr->sector,
1772 cvptr->buffer [3], cvptr->buffer [4], cvptr->buffer [5], cvptr->buffer [6]);
1773
1774 next_sector (cvptr, cvptr->device->units /* address the next sector of the last unit used */
1775 + S1_UNIT (cvptr->spd_unit));
1776 break;
1777
1778
1779 case Set_File_Mask:
1780 cvptr->file_mask = CM_FILE_MASK (inbound_data); /* save the supplied file mask */
1781
1782 outbound |= CM_RETRY (inbound_data); /* return the retry count */
1783
1784 set_completion (cvptr, cuptr, Normal_Completion); /* schedule the command completion */
1785
1786 tpprintf (cvptr->device, DL_DEB_CMD, "%s to %sretries %u\n",
1787 opcode_name [Set_File_Mask], fmt_bitset (cvptr->file_mask, file_mask_format),
1788 CM_RETRY (inbound_data));
1789 break;
1790
1791
1792 case Request_Disc_Address:
1793 set_address (cvptr, 0); /* set the controller's CHS values into the buffer */
1794
1795 tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s returns cylinder %u head %u sector %u\n",
1796 unit, opcode_name [Request_Disc_Address], cvptr->cylinder, cvptr->head, cvptr->sector);
1797 break;
1798
1799
1800 case End:
1801 tpprintf (cvptr->device, DL_DEB_CMD, "%s\n", opcode_name [End]);
1802
1803 end_command (cvptr, NULL, Normal_Completion); /* end the command and idle the controller */
1804 break;
1805
1806
1807 case Wakeup:
1808 set_completion (cvptr, cuptr, Unit_Available); /* schedule the command completion */
1809
1810 tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s\n",
1811 unit, opcode_name [Wakeup]);
1812 break;
1813
1814
1815 /* these commands wait for seek completion before starting */
1816
1817 case Read_Without_Verify:
1818 cvptr->verify = FALSE; /* do not verify until a track is crossed */
1819 inbound_data &= ~CM_SPD_MASK; /* clear the SPD bits to avoid changing the state */
1820
1821 /* fall through into the Initialize case */
1822
1823 case Initialize:
1824 cvptr->spd_unit |= CM_SPD (inbound_data); /* merge the SPD flags with the unit */
1825
1826 /* fall through into the read/write cases */
1827
1828 case Read:
1829 case Read_Full_Sector:
1830 case Write:
1831 case Write_Full_Sector:
1832 if (duptr->PHASE == Seek_Phase) /* if the unit is currently seeking */
1833 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command waiting for seek completion\n",
1834 unit, opcode_name [cvptr->opcode]);
1835
1836 else /* otherwise the unit is idle */
1837 set_rotation (cvptr, duptr); /* so set up the rotation phase and latency */
1838 break;
1839
1840
1841 /* these commands take parameters but otherwise require no preliminary work */
1842
1843 case Seek:
1844 case Verify:
1845 case Address_Record:
1846 case Read_With_Offset:
1847 case Load_TIO_Register:
1848 break;
1849
1850
1851 case Invalid_Opcode: /* for completeness; invalid commands are not dispatched */
1852 break;
1853 }
1854 }
1855
1856
1857 if (cvptr->state == Busy_State) { /* if the command has not completed immediately */
1858 if (cuptr->wait != NO_EVENT && cvptr->type == MAC) /* then if the controller unit is scheduled */
1859 activate_unit (cvptr, cuptr); /* then activate it */
1860
1861 if (duptr && duptr->wait != NO_EVENT) /* and if the drive unit is valid and scheduled */
1862 activate_unit (cvptr, duptr); /* then activate it as well */
1863 }
1864
1865 if (outbound & WRTIO) /* if status is expected immediately */
1866 outbound |= S1_STATUS (cvptr->status) | cvptr->spd_unit; /* then return the Status-1 value */
1867
1868 return outbound; /* return the data word and function set */
1869 }
1870
1871
1872 /* Continue the current command.
1873
1874 This routine simulates continuing execution of the controller microcode for
1875 the current command. It's called whenever the controller has had to wait for
1876 action from the CPU interface or the drive unit, and that action has now
1877 occurred. Typically, this would be whenever the interface flag status
1878 changes, or a unit's event service has been entered. It returns a set of
1879 action functions and a data word to the caller. It also sets up the next
1880 phase of operation on the controller and/or drive unit and schedules the
1881 unit(s) as appropriate.
1882
1883 On entry, the "uptr" parameter is set to NULL if the controller was called
1884 for a CPU interface action, or it points to the unit whose event service was
1885 just called; this may be either the controller unit or a drive unit. The
1886 "inbound_flags" and "inbound_data" parameters contain the CPU interface flags
1887 and data buffer values.
1888
1889 If the entry is for a unit service, the unit number of the drive requesting
1890 service is determined. If the entry is for the CPU interface, the controller
1891 is checked; if it's idle, the routine returns because no command is in
1892 progress.
1893
1894 While a unit is activated, the current phase indicates the reason for the
1895 activation, i.e., what the simulated drive is "doing" at the moment, as
1896 follows:
1897
1898 Idle_Phase -- waiting for the next command to be issued (note that
1899 this phase, which indicates that the unit is not
1900 scheduled, is distinct from the controller Idle_State,
1901 which indicates that the controller itself is idle)
1902
1903 Parameter_Phase -- waiting for a parameter to be transferred to or from
1904 the interface
1905
1906 Seek_Phase -- waiting for a seek to complete (explicit or automatic)
1907
1908 Rotate_Phase -- waiting for the target sector to arrive under the head
1909
1910 Data_Phase -- waiting for the interface to accept or return the next
1911 data word to be transferred to or from the drive
1912
1913 Intersector_Phase -- waiting for the controller to finish executing the
1914 end-of-sector microcode
1915
1916 End_Phase -- waiting for the controller to finish executing the
1917 microcode corresponding to the current command
1918
1919 Depending on the current command opcode and phase, a number of actions may be
1920 taken:
1921
1922 Idle_Phase -- If the controller unit is being serviced, then the 1.74
1923 second command wait timer has expired while waiting for a new command.
1924 Reset the file mask and idle the controller.
1925
1926 Parameter_Phase -- If the controller unit is being serviced, then the 1.74
1927 second command wait timer has expired while waiting for a parameter from
1928 the CPU. Reset the file mask and idle the controller. Otherwise, for
1929 outbound parameters, return the next word from the sector buffer and
1930 restart the timer; if the last word has been sent, end the command. For
1931 inbound parameters, store the next word in the appropriate controller state
1932 variable; if the last word has been received, end the command or set up the
1933 next operation phase (seek, rotate, etc.).
1934
1935 Seek_Phase -- If a Seek or Recalibrate has completed, set Drive Attention
1936 status. All other commands have been waiting for seek completion before
1937 starting, so set up the rotate phase to begin the command.
1938
1939 Rotate_Phase -- Set up the read or write of the current sector. For all
1940 commands except Verify, proceed to the data phase to begin the data
1941 transfer. For Verify, skip the data phase and proceed directly to the
1942 end-of-sector processing, but schedule that event as though the full sector
1943 rotation time had elapsed.
1944
1945 Data_Phase -- For read transfers, return the next word from the sector
1946 buffer, or for write transfers, store the next word into the sector buffer,
1947 and schedule the next data phase transfer if the CPU has not indicated an
1948 end-of-data condition. If it has, or if the last word of the sector has
1949 been transmitted, schedule the intersector phase.
1950
1951 Intersector_Phase -- Complete the read or write of the current sector. If
1952 the CPU has indicated an end-of-data condition, end the command.
1953 Otherwise, address the next sector and schedule the rotate phase.
1954
1955 End_Phase -- End the command. The end phase is used to provide a
1956 controller delay when an operation has no other command phases.
1957
1958 At the completion of the current phase, the next phase is scheduled, if
1959 required, before returning the appropriate function set and data word to the
1960 caller.
1961
1962 The commands employ the various phases as follows:
1963 Inter
1964 Command Param Seek Rotate Data sector End
1965 +------------------------+-------+------+--------+------+--------+-----+
1966 | Cold Load Read | - | D | D | D | D | - |
1967 | Recalibrate | - | D | - | - | - | - |
1968 | Seek | c | D | - | - | - | - |
1969 | Request Status | c | - | - | - | - | - |
1970 | Request Sector Address | c | - | - | - | - | - |
1971 | Read | - | - | D | D | D | - |
1972 | Read Full Sector | - | - | D | D | D | - |
1973 | Verify | c | - | D | - | D | - |
1974 | Write | - | - | D | D | D | - |
1975 | Write Full Sector | - | - | D | D | D | - |
1976 | Clear | - | - | - | - | - | C |
1977 | Initialize | - | - | D | D | D | - |
1978 | Address Record | c | - | - | - | - | - |
1979 | Request Syndrome | c | - | - | - | - | - |
1980 | Read With Offset | c | - | D | D | D | - |
1981 | Set File Mask | - | - | - | - | - | C |
1982 | Invalid Opcode | - | - | - | - | - | C |
1983 | Read Without Verify | - | - | D | D | D | - |
1984 | Load TIO Register | c | - | - | - | - | - |
1985 | Request Disc Address | c | - | - | - | - | - |
1986 | End | - | - | - | - | - | - |
1987 | Wakeup | - | - | - | - | - | C |
1988 +------------------------+-------+------+--------+------+--------+-----+
1989
1990 Key:
1991 C = controller unit is scheduled
1992 c = controller is called directly by the CPU interface
1993 D = drive unit is scheduled
1994 - = the phase is not used
1995
1996
1997 Implementation notes:
1998
1999 1. The "%.0u" print specification in the trace call absorbs the zero "unit"
2000 value parameter without printing when the controller unit is specified.
2001
2002 2. The Seek command does not check for Access Not Ready before issuing the
2003 seek, so if a prior seek is in progress, the drive will reject it with a
2004 Seek Check error. However, the parameters (e.g., controller CHS
2005 addresses) are still set as though the command had succeeded.
2006
2007 A Seek command will return to the Poll Loop with Seek Check status set.
2008 When the seek in progress completes, the controller will interrupt with
2009 Drive Attention status. The controller address will differ from the
2010 drive address, so it's incumbent upon the caller to issue a Request
2011 Status command after the seek, which will return Status-2 Error status.
2012
2013 3. The set of interface functions to assert on command completion is
2014 normally specified by the End_Phase entry in the cmd_functions table,
2015 regardless of whether or not a command has an end phase. However, the
2016 Request Syndrome command returns either Correctable Data Error or
2017 Uncorrectable Data Error for normal command completion. These status
2018 returns would normally include DVEND to indicate that the command should
2019 be retried, but that's wrong for Request Syndrome, so we explicitly
2020 override the function set for this command.
2021
2022 4. Command completion must be detected by the controller state changing to
2023 "not busy" rather than simply being "not busy" at the end of the routine.
2024 Otherwise, a seek that completes while the controller is waiting for a
2025 command would re-issue the end phase functions.
2026
2027 5. The disc is a synchronous device, so overrun or underrun can occur if the
2028 interface is not ready when the controller must transfer data. There are
2029 four conditions that lead to an overrun or underrun:
2030
2031 a. The controller is ready with a disc read word (IFCLK * IFIN), but
2032 the interface buffer is full (DTRDY).
2033
2034 b. The controller needs a disc write word (IFCLK * IFOUT), but the
2035 interface buffer is empty (~DTRDY).
2036
2037 c. The CPU attempts to read a word, but the interface buffer is empty
2038 (~DTRDY).
2039
2040 d. The CPU attempts to write a word, but the interface buffer is full
2041 (DTRDY).
2042
2043 The 13037 controller ORs the interface-supplied OVRUN signal with an
2044 internal overrun latch that sets on condition 2 above (write underrun).
2045 However, both the 13175A HP 1000 interface and the 30229B HP 3000
2046 interface assert OVRUN for all four conditions, so the latch is not
2047 simulated.
2048
2049 6. Not all changes of CPU interface flag status are significant. If the
2050 routine is called when it isn't needed, the routine simply returns with
2051 no action.
2052 */
2053
continue_command(CVPTR cvptr,UNIT * uptr,CNTLR_FLAG_SET inbound_flags,CNTLR_IBUS inbound_data)2054 static CNTLR_IFN_IBUS continue_command (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET inbound_flags, CNTLR_IBUS inbound_data)
2055 {
2056 const t_bool service_entry = (uptr != NULL); /* set TRUE if entered via unit service */
2057 CNTLR_OPCODE opcode;
2058 CNTLR_PHASE phase;
2059 CNTLR_IFN_IBUS outbound;
2060 t_bool controller_service, controller_was_busy;
2061 int32 unit;
2062 uint32 sector_count;
2063
2064 if (service_entry) { /* if this is an event service entry */
2065 unit = (int32) (uptr - cvptr->device->units); /* then get the unit number */
2066
2067 controller_service = (uptr == CNTLR_UPTR /* set TRUE if the controller is being serviced */
2068 && cvptr->type == MAC);
2069 }
2070
2071 else if (CNTLR_UPTR->PHASE == Idle_Phase) /* otherwise if this interface entry isn't needed */
2072 return NO_ACTION; /* then quit as there's nothing to do */
2073
2074 else { /* otherwise the controller is expecting the entry */
2075 uptr = CNTLR_UPTR; /* set up to use the controller unit */
2076 unit = CNTLR_UNIT; /* and unit number */
2077 controller_service = FALSE; /* but note that this isn't a service entry */
2078 }
2079
2080
2081 opcode = (CNTLR_OPCODE) uptr->OPCODE; /* get the current opcode */
2082 phase = (CNTLR_PHASE) uptr->PHASE; /* and command phase */
2083
2084 if (controller_service == FALSE || phase == End_Phase)
2085 tpprintf (cvptr->device, DL_DEB_STATE, (unit == CNTLR_UNIT
2086 ? "Controller unit%.0d %s %s phase entered from %s\n"
2087 : "Unit %d %s %s phase entered from %s\n"),
2088 (unit == CNTLR_UNIT ? 0 : unit), opcode_name [opcode], phase_name [phase],
2089 (service_entry ? "service" : "interface"));
2090
2091 controller_was_busy = (cvptr->state == Busy_State); /* set TRUE if the controller was busy on entry */
2092
2093 outbound = cmd_functions [opcode] [phase]; /* set up the initial function return set */
2094
2095
2096 switch (phase) { /* dispatch the phase */
2097
2098 case Idle_Phase: /* the command wait timer has expired */
2099 clear_controller (cvptr, Timeout_Clear); /* so idle the controller and clear the file mask */
2100
2101 outbound = NO_FUNCTIONS; /* clear the function set for an idle return */
2102
2103 tpprintf (cvptr->device, DL_DEB_INCO, "Controller command wait timed out\n");
2104 break;
2105
2106
2107 case Parameter_Phase:
2108 if (controller_service) { /* if the parameter wait timer has expired */
2109 clear_controller (cvptr, Timeout_Clear); /* then idle the controller and clear the file mask */
2110
2111 outbound = NO_FUNCTIONS; /* clear the function set for an idle return */
2112
2113 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command aborted with parameter wait timeout\n",
2114 CM_UNIT (cvptr->spd_unit), opcode_name [opcode]);
2115 }
2116
2117 else switch (opcode) { /* otherwise dispatch the command */
2118
2119 case Request_Status: /* these commands */
2120 case Request_Disc_Address: /* return parameters */
2121 case Request_Sector_Address: /* to the interface */
2122 case Request_Syndrome:
2123 if (cvptr->length == 0) /* if the last parameter has been sent */
2124 end_command (cvptr, uptr, cvptr->status); /* then terminate the command with the preset status */
2125
2126 else { /* otherwise there are more to send */
2127 outbound |= cvptr->buffer [cvptr->index++]; /* so return the next value from the buffer */
2128 cvptr->length = cvptr->length - 1; /* and drop the parameter count */
2129
2130 wait_timer (cvptr, SET); /* restart the parameter timer */
2131 }
2132 break;
2133
2134
2135 case Seek: /* these commands receive parameters */
2136 case Address_Record: /* from the interface */
2137 cvptr->buffer [cvptr->index++] = /* save the current one in the buffer */
2138 (DL_BUFFER) inbound_data;
2139 cvptr->length = cvptr->length - 1; /* and drop the parameter count */
2140
2141 if (cvptr->length > 0) /* if another parameter is expected */
2142 wait_timer (cvptr, SET); /* then restart the parameter timer */
2143
2144 else { /* otherwise all parameters are in */
2145 cvptr->cylinder = cvptr->buffer [0]; /* so fill in the supplied cylinder */
2146 cvptr->head = PI_HEAD (cvptr->buffer [1]); /* and head */
2147 cvptr->sector = PI_SECTOR (cvptr->buffer [1]); /* and sector addresses */
2148
2149 if (opcode == Address_Record) { /* if this is an Address Record command */
2150 cvptr->eoc = CLEAR; /* then clear the end-of-cylinder flag */
2151
2152 tpprintf (cvptr->device, DL_DEB_CMD, "%s to cylinder %u head %u sector %u\n",
2153 opcode_name [Address_Record],
2154 cvptr->cylinder, cvptr->head, cvptr->sector);
2155
2156 end_command (cvptr, uptr, /* the command is now complete */
2157 Normal_Completion);
2158 }
2159
2160 else { /* otherwise it's a Seek command */
2161 tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s to cylinder %u head %u sector %u\n",
2162 CM_UNIT (cvptr->spd_unit), opcode_name [Seek],
2163 cvptr->cylinder, cvptr->head, cvptr->sector);
2164
2165 uptr = cvptr->device->units /* get the target unit */
2166 + CM_UNIT (cvptr->spd_unit);
2167
2168 if (start_seek (cvptr, uptr) == FALSE) /* start the seek; if it failed, */
2169 end_command (cvptr, uptr, /* then report the error */
2170 Status_2_Error);
2171
2172 else if (cvptr->type == MAC) /* otherwise if this a MAC controller */
2173 end_command (cvptr, uptr, /* then complete the command and idle the controller */
2174 Normal_Completion);
2175 } /* otherwise an ICD command ends when the seek completes */
2176 }
2177 break;
2178
2179
2180 case Verify:
2181 if (inbound_data == 0) /* if the sector count is zero */
2182 sector_count = 65536; /* then use the rollover count */
2183 else /* otherwise */
2184 sector_count = inbound_data; /* use the count as is */
2185
2186 cvptr->count = sector_count * WORDS_PER_SECTOR; /* convert to the number of words to verify */
2187
2188 tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s %u sector%s\n",
2189 CM_UNIT (cvptr->spd_unit), opcode_name [Verify],
2190 sector_count, (sector_count == 1 ? "" : "s"));
2191
2192 wait_timer (cvptr, CLEAR); /* stop the parameter timer */
2193
2194 uptr = cvptr->device->units /* get the target unit */
2195 + CM_UNIT (cvptr->spd_unit);
2196
2197 if (uptr->PHASE == Seek_Phase) { /* if a seek is in progress, */
2198 uptr->wait = NO_EVENT; /* then wait for it to complete */
2199
2200 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command waiting for seek completion\n",
2201 CM_UNIT (cvptr->spd_unit), opcode_name [Verify]);
2202 }
2203
2204 else /* otherwise the unit is idle */
2205 set_rotation (cvptr, uptr); /* so set up the rotation phase and latency */
2206 break;
2207
2208
2209 case Read_With_Offset:
2210 tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s using %soffset %+d\n",
2211 CM_UNIT (cvptr->spd_unit), opcode_name [Read_With_Offset],
2212 fmt_bitset (inbound_data, offset_format),
2213 (inbound_data & PI_NEG_OFFSET ? - (int) PI_OFFSET (inbound_data)
2214 : (int) PI_OFFSET (inbound_data)));
2215
2216 wait_timer (cvptr, CLEAR); /* stop the parameter timer */
2217
2218 uptr = cvptr->device->units /* get the target unit */
2219 + CM_UNIT (cvptr->spd_unit);
2220
2221 if (uptr->PHASE == Seek_Phase) { /* if a seek is in progress, */
2222 uptr->wait = NO_EVENT; /* then wait for it to complete */
2223
2224 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command waiting for seek completion\n",
2225 CM_UNIT (cvptr->spd_unit), opcode_name [Read_With_Offset]);
2226 }
2227
2228 else { /* otherwise the unit is idle */
2229 uptr->PHASE = Seek_Phase; /* so schedule the seek phase */
2230 uptr->wait = cvptr->dlyptr->seek_one; /* with the offset positioning delay */
2231 }
2232 break;
2233
2234
2235 case Load_TIO_Register:
2236 wait_timer (cvptr, CLEAR); /* stop the parameter timer */
2237
2238 tpprintf (cvptr->device, DL_DEB_CMD, "%s with %06o\n",
2239 opcode_name [Load_TIO_Register], inbound_data);
2240
2241 end_command (cvptr, uptr, Normal_Completion); /* complete the command */
2242
2243 return inbound_data /* return the supplied TIO value */
2244 | cmd_functions [Load_TIO_Register] [End_Phase];
2245 break;
2246
2247
2248 default: /* the remaining commands */
2249 break; /* do not have a parameter phase */
2250 }
2251
2252 break;
2253
2254
2255 case Seek_Phase:
2256 switch (opcode) { /* dispatch the command */
2257
2258 case Recalibrate:
2259 case Seek:
2260 if (cvptr->type == MAC) { /* if this a MAC controller */
2261 uptr->STATUS |= S2_ATTENTION; /* set Attention in the unit status */
2262 uptr->PHASE = Idle_Phase; /* and idle the drive */
2263 }
2264
2265 else /* otherwise this is an ICD or CS/80 drive */
2266 end_command (cvptr, uptr, Drive_Attention); /* so seeks end with Drive Attention status */
2267 break;
2268
2269
2270 case Cold_Load_Read:
2271 cvptr->file_mask = CM_SPARE_EN; /* enable sparing in surface mode without auto-seek */
2272
2273 /* fall through into the default case */
2274
2275 default: /* a command was waiting on seek completion */
2276 set_rotation (cvptr, uptr); /* so set up the rotation phase and latency */
2277 break;
2278 }
2279
2280 break;
2281
2282
2283 case Rotate_Phase:
2284 switch (opcode) { /* dispatch the command */
2285
2286 case Write:
2287 case Write_Full_Sector:
2288 case Initialize:
2289 start_write (cvptr, uptr); /* start the sector write */
2290 break;
2291
2292
2293 case Read:
2294 case Read_Full_Sector:
2295 case Read_With_Offset:
2296 case Read_Without_Verify:
2297 case Cold_Load_Read:
2298 start_read (cvptr, uptr, inbound_flags); /* start the sector read */
2299 break;
2300
2301
2302 case Verify:
2303 inbound_flags &= ~EOD; /* EOD is not relevant for Verify */
2304
2305 if (start_read (cvptr, uptr, inbound_flags)) { /* if the sector read was set up successfully */
2306 uptr->PHASE = Intersector_Phase; /* then skip the data phase */
2307 uptr->wait = cvptr->dlyptr->sector_full; /* and reschedule for the sector read time */
2308 }
2309 break;
2310
2311
2312 default: /* the remaining commands */
2313 break; /* do not have a rotate phase */
2314 }
2315
2316 break;
2317
2318
2319 case Data_Phase:
2320 if (inbound_flags & EOD) /* if the transfer has ended */
2321 outbound = NO_FUNCTIONS; /* then don't assert IFIN/IFOUT on return */
2322
2323 switch (opcode) { /* dispatch the command */
2324
2325 case Read:
2326 case Read_With_Offset:
2327 case Read_Without_Verify:
2328 case Read_Full_Sector:
2329 case Cold_Load_Read:
2330 if ((inbound_flags & EOD) == NO_FLAGS) { /* if the transfer continues */
2331 outbound |= cvptr->buffer [cvptr->index++]; /* then get the next word from the buffer */
2332
2333 cvptr->count = cvptr->count + 1; /* count the */
2334 cvptr->length = cvptr->length - 1; /* transfer */
2335
2336 tpprintf (cvptr->device, DL_DEB_XFER, "Unit %d %s word %u is %06o\n",
2337 unit, opcode_name [opcode],
2338 cvptr->count, DLIBUS (outbound));
2339 }
2340
2341 uptr->wait = cvptr->dlyptr->data_xfer; /* set the transfer delay */
2342
2343 if (cvptr->length == 0 || inbound_flags & EOD) { /* if the buffer is empty or the transfer is done */
2344 uptr->PHASE = Intersector_Phase; /* then set up the intersector phase */
2345
2346 if (cvptr->device->flags & DEV_REALTIME) /* if we're in realistic timing mode */
2347 uptr->wait = uptr->wait /* then account for the actual delay */
2348 * (cvptr->length + cmd_props [opcode].postamble_size);
2349 }
2350 break;
2351
2352
2353 case Write:
2354 case Write_Full_Sector:
2355 case Initialize:
2356 if ((inbound_flags & EOD) == NO_FLAGS) { /* if the transfer continues */
2357 cvptr->buffer [cvptr->index++] = /* then store the next word in the buffer */
2358 (DL_BUFFER) inbound_data;
2359
2360 cvptr->count = cvptr->count + 1; /* count the */
2361 cvptr->length = cvptr->length - 1; /* transfer */
2362
2363 tpprintf (cvptr->device, DL_DEB_XFER, "Unit %d %s word %u is %06o\n",
2364 unit, opcode_name [opcode],
2365 cvptr->count, inbound_data);
2366 }
2367
2368 uptr->wait = cvptr->dlyptr->data_xfer; /* set the transfer delay */
2369
2370 if (cvptr->length == 0 || inbound_flags & EOD) { /* if the buffer is empty or the transfer is done */
2371 uptr->PHASE = Intersector_Phase; /* then set up the intersector phase */
2372
2373 if (cvptr->device->flags & DEV_REALTIME) /* if we're in realistic timing mode */
2374 uptr->wait = uptr->wait /* then account for the actual delay */
2375 * (cvptr->length + cmd_props [opcode].postamble_size);
2376 }
2377 break;
2378
2379
2380 default: /* the remaining commands */
2381 break; /* do not have a data phase */
2382 }
2383
2384 break;
2385
2386
2387 case Intersector_Phase:
2388 switch (opcode) { /* dispatch the command */
2389
2390 case Read:
2391 case Read_With_Offset:
2392 case Read_Without_Verify:
2393 case Read_Full_Sector:
2394 case Cold_Load_Read:
2395 end_read (cvptr, uptr, inbound_flags); /* end the sector read */
2396 break;
2397
2398
2399 case Write:
2400 case Write_Full_Sector:
2401 case Initialize:
2402 end_write (cvptr, uptr, inbound_flags); /* end the sector write */
2403 break;
2404
2405
2406 case Verify:
2407 cvptr->count = cvptr->count - WORDS_PER_SECTOR; /* decrement the word count */
2408
2409 if (cvptr->count > 0) /* if there more sectors to verify */
2410 inbound_flags &= ~EOD; /* then this is not the end of data */
2411 else /* otherwise the command is complete */
2412 inbound_flags |= EOD; /* and this is the end of data */
2413
2414 end_read (cvptr, uptr, inbound_flags); /* end the sector read */
2415 break;
2416
2417
2418 default: /* the remaining commands */
2419 break; /* do not have an intersector phase */
2420 }
2421
2422 break;
2423
2424
2425 case End_Phase:
2426 end_command (cvptr, uptr, cvptr->status); /* complete the command with the preset status */
2427 break;
2428 }
2429
2430
2431 if (uptr->wait != NO_EVENT) /* if the unit has been scheduled */
2432 activate_unit (cvptr, uptr); /* then activate it */
2433
2434 if (controller_was_busy && cvptr->state != Busy_State) { /* if the command has just completed */
2435 if (cvptr->status == Normal_Completion /* then if the command completed normally */
2436 || opcode == Request_Syndrome) /* or it was a Request Syndrome command */
2437 outbound = cmd_functions [opcode] [End_Phase]; /* then use the normal exit function set */
2438 else /* otherwise */
2439 outbound = status_functions [cvptr->status]; /* the function set depends on the status */
2440
2441 if (outbound & WRTIO) /* if the TIO register will be written */
2442 outbound |= S1_STATUS (cvptr->status) | cvptr->spd_unit; /* then include the Status-1 value */
2443 }
2444
2445 return outbound; /* return the data word and function set */
2446 }
2447
2448
2449 /* Poll the drives for Attention status.
2450
2451 MAC controllers complete their Seek and Recalibrate commands when the seeks
2452 are initiated, so that other drives may be serviced during the waits. A
2453 drive will set its Attention status when its seek completes, and the
2454 controller must poll the drives for attention requests when it is idle and
2455 interrupts are allowed by the CPU interface.
2456
2457 Starting with the last unit that had previously requested attention, each
2458 drive is checked in sequence. If a drive has its Attention status set, the
2459 controller saves its unit number, sets the result status to Drive Attention,
2460 and enters the command wait state. The routine returns a function set that
2461 indicates that an interrupt should be generated. The next time the routine
2462 is called, the poll begins with the last unit that requested attention, so
2463 that each unit is given an equal chance to respond.
2464
2465 If no unit is requesting attention, the routine returns an empty function set
2466 to indicate that no interrupt should be generated.
2467
2468 ICD controllers do not call this routine, because each controller waits for
2469 seek completion on its dedicated drive before completing the associated Seek
2470 or Recalibrate command.
2471 */
2472
poll_drives(CVPTR cvptr)2473 static CNTLR_IFN_IBUS poll_drives (CVPTR cvptr)
2474 {
2475 uint32 unit;
2476 UNIT *units = cvptr->device->units;
2477
2478 tpprintf (cvptr->device, DL_DEB_INCO, "Controller polled drives for attention\n");
2479
2480 for (unit = 0; unit <= DL_MAXDRIVE; unit++) { /* check each unit in turn */
2481 cvptr->poll_unit = /* start with the last unit checked */
2482 (cvptr->poll_unit + 1) % (DL_MAXDRIVE + 1); /* and cycle back to unit 0 */
2483
2484 if (units [cvptr->poll_unit].STATUS & S2_ATTENTION) { /* if the unit is requesting attention, */
2485 units [cvptr->poll_unit].STATUS &= ~S2_ATTENTION; /* clear the Attention status */
2486
2487 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u requested attention\n",
2488 cvptr->poll_unit);
2489
2490 cvptr->spd_unit = cvptr->poll_unit; /* set the controller's unit number */
2491 cvptr->status = Drive_Attention; /* and status */
2492
2493 cvptr->state = Wait_State; /* set the controller state to waiting */
2494 wait_timer (cvptr, SET); /* start the command wait timer */
2495
2496 return status_functions [Drive_Attention] /* tell the caller to interrupt */
2497 | S1_STATUS (cvptr->status) | cvptr->spd_unit; /* and include the Status-1 value */
2498 }
2499 }
2500
2501 return NO_ACTION; /* no drives have attention set */
2502 }
2503
2504
2505 /* Clear the controller.
2506
2507 A "hard", "timeout", or "soft" clear is performed on the indicated controller
2508 as specified by the "clear_type" parameter.
2509
2510 In hardware, four conditions clear the 13037 controller:
2511
2512 - an initial application of power
2513 - an assertion of the CLEAR signal by the CPU interface
2514 - a timeout of the command wait timer
2515 - a programmed Clear command
2516
2517 The first two conditions, called "hard clears," are equivalent and cause a
2518 firmware restart with the PWRON flag set. The 13175 interface for the HP
2519 1000 asserts the CLEAR signal in response to the backplane CRS signal if the
2520 PRESET jumper is installed in the enabled position (which is the usual case).
2521 The 30229B interface for the HP 3000 asserts CLEAR in response to an IORESET
2522 signal or a programmed Master Reset if the PRESET DISABLE jumper is installed
2523 in the enabled position.
2524
2525 The third condition, a "timeout clear", also causes a firmware restart but
2526 with the PWRON flag clear. The last condition, a "soft clear" is executed in
2527 the command handler and therefore returns to the Command Wait Loop instead of
2528 the Poll Loop.
2529
2530 For a hard clear, the 13037 controller will:
2531
2532 - disconnect the CPU interface
2533 - zero the controller RAM (no drives held, last polled unit number reset)
2534 - clear the clock offset
2535 - clear the file mask
2536 - issue a Controller Preset to clear all connected drives
2537 - enter the Poll Loop (which clears the controller status)
2538
2539 For a timeout clear, the 13037 controller will:
2540
2541 - disconnect the CPU interface
2542 - clear the hold bits of any drives held by the interface that timed out
2543 - clear the clock offset
2544 - clear the file mask
2545 - enter the Poll Loop (which clears the controller status)
2546
2547 For a programmed "soft" clear, the 13037 controller will:
2548
2549 - clear the controller status
2550 - issue a Controller Preset to clear all connected drives
2551 - enter the Command Wait Loop
2552
2553 Controller Preset is a tag bus command that is sent to all drives connected
2554 to the controller. Each drive will:
2555
2556 - disconnect from the controller
2557 - clear its internal drive faults
2558 - clear its head and sector registers
2559 - clear its illegal head and sector flip-flops
2560 - reset its seek check, first status, drive fault, and attention status
2561
2562 On a 7905 or 7906 drive, clearing the head register will change Read-Only
2563 status to reflect the position of the PROTECT LOWER DISC switch.
2564
2565 In simulation, a hard clear occurs when an SCP RESET command is entered, or a
2566 programmed CLC 0 instruction or Master Clear is executed. A timeout clear
2567 occurs when the command or parameter wait timer expires. A soft clear occurs
2568 when a programmed Clear command is issued.
2569
2570 Because the controller execution state is implemented by scheduling command
2571 phases for the target or controller unit, a simulated firmware restart must
2572 abort any in-process activation. However, a firmware restart does not affect
2573 seeks in progress, so these must be allowed to continue to completion so that
2574 their Attention requests will be honored.
2575
2576
2577 Implementation notes:
2578
2579 1. The specific 13365 controller actions on hard or soft clears are not
2580 documented. Therefore, an ICD controller clear is handled as a MAC
2581 controller clear, except that only the current drive is preset (as an ICD
2582 controller manages only a single drive).
2583
2584 2. Neither hard nor soft clears affect the controller flags (e.g., EOC) or
2585 registers (e.g., cylinder address).
2586
2587 3. In simulation, an internal seek, such as an auto-seek during a Read
2588 command or the initial seek during a Cold Load Read command, will be
2589 aborted for a hard clear, whereas in hardware it would complete normally.
2590 This is OK, however, because an internal seek always clears the drive's
2591 Attention status on completion, so aborting the simulated seek is
2592 equivalent to an immediate seek completion.
2593
2594 4. If a drive unit is disabled, it is still cleared. A unit cannot be
2595 disabled while it is active, so it must be in the idle state while
2596 disabled. Clearing the status keeps it consistent in case it is
2597 reenabled later.
2598
2599 5. A soft clear does not abort commands in progress on a drive unit.
2600 However, a soft clear is a result of a programmed command that can only
2601 be issued when the prior command has completed (except for Seek and
2602 Recalibrate commands, which are never aborted).
2603
2604 6. In simulation, a Controller Preset only resets the specified status bits,
2605 as the remainder of the hardware actions are not implemented.
2606 */
2607
clear_controller(CVPTR cvptr,CNTLR_CLEAR clear_type)2608 static void clear_controller (CVPTR cvptr, CNTLR_CLEAR clear_type)
2609 {
2610 uint32 unit_count;
2611 UNIT *uptr;
2612
2613 if (clear_type == Timeout_Clear) { /* if this is a timeout clear */
2614 cvptr->file_mask = 0; /* then clear the file mask */
2615 idle_controller (cvptr); /* and idle the controller */
2616 }
2617
2618 else { /* otherwise */
2619 if (clear_type == Hard_Clear) { /* if this a hard clear */
2620 cvptr->file_mask = 0; /* then clear the file mask */
2621
2622 if (cvptr->type == MAC) /* if this is a MAC controller */
2623 cvptr->poll_unit = 0; /* then clear the last unit polled too */
2624
2625 idle_controller (cvptr); /* idle the controller */
2626 }
2627
2628 else /* otherwise it's a soft clear */
2629 cvptr->status = Normal_Completion; /* so clear the status explicitly */
2630
2631 if (cvptr->type == MAC) { /* if this a MAC controller */
2632 uptr = cvptr->device->units; /* then preset all units */
2633 unit_count = cvptr->device->numunits - 1; /* except the controller unit */
2634 }
2635
2636 else { /* otherwise preset */
2637 uptr = cvptr->device->units + cvptr->poll_unit; /* only the single unit */
2638 unit_count = 1; /* dedicated to the controller */
2639 }
2640
2641 while (unit_count > 0) { /* preset each drive in turn */
2642 if (uptr->PHASE != Idle_Phase /* if the unit is active */
2643 && uptr->OPCODE != Seek /* but not seeking */
2644 && uptr->OPCODE != Recalibrate) { /* or recalibrating */
2645 sim_cancel (uptr); /* then cancel the unit event */
2646 uptr->PHASE = Idle_Phase; /* and idle it */
2647 }
2648
2649 uptr->STATUS &= ~(S2_CPS | S2_READ_ONLY); /* do a "Controller Preset" on the unit */
2650
2651 if (uptr->flags & UNIT_PROT_U) /* if the (upper) heads are protected */
2652 uptr->STATUS |= S2_READ_ONLY; /* then set read-only status */
2653
2654 uptr++; /* point at the next unit */
2655 unit_count = unit_count - 1; /* and count the unit just cleared */
2656 }
2657 }
2658
2659 return;
2660 }
2661
2662
2663
2664 /* Disc library global utility routines */
2665
2666
2667 /* Return the name of an opcode.
2668
2669 A string representing the supplied controller opcode is returned to the
2670 caller. If the opcode is illegal or undefined for the indicated controller,
2671 the string "Invalid" is returned.
2672 */
2673
dl_opcode_name(CNTLR_TYPE controller,CNTLR_OPCODE opcode)2674 const char *dl_opcode_name (CNTLR_TYPE controller, CNTLR_OPCODE opcode)
2675 {
2676 if (controller <= LAST_CNTLR /* if the controller type is legal */
2677 && opcode <= LAST_OPCODE /* and the opcode is legal */
2678 && cmd_props [opcode].valid [controller]) /* and is defined for this controller, */
2679 return opcode_name [opcode]; /* then return the opcode name */
2680 else /* otherwise the type or opcode is illegal */
2681 return invalid_name; /* so return an error indication */
2682 }
2683
2684
2685 /* Return the name of a command result status.
2686
2687 A string representing the supplied command result status is returned to the
2688 caller. If the status is illegal or undefined, the string "Invalid" is
2689 returned.
2690 */
2691
dl_status_name(CNTLR_STATUS status)2692 const char *dl_status_name (CNTLR_STATUS status)
2693 {
2694 if (status <= Drive_Attention && status_name [status]) /* if the status is legal */
2695 return status_name [status]; /* then return the status name */
2696 else /* otherwise the status is illegal */
2697 return invalid_name; /* so return an error indication */
2698 }
2699
2700
2701
2702 /* Disc library global SCP support routines */
2703
2704
2705 /* Attach a disc image file to a unit.
2706
2707 The file specified by the supplied filename is attached to the indicated
2708 unit. If the attach was successful, the heads are loaded on the drive.
2709
2710
2711 Implementation notes:
2712
2713 1. The pointer to the appropriate event delay times is set in case we are
2714 being called during a RESTORE command (the assignment is redundant
2715 otherwise).
2716 */
2717
dl_attach(CVPTR cvptr,UNIT * uptr,char * cptr)2718 t_stat dl_attach (CVPTR cvptr, UNIT *uptr, char *cptr)
2719 {
2720 t_stat result;
2721
2722 result = attach_unit (uptr, cptr); /* attach the unit */
2723
2724 if (result == SCPE_OK) /* if the attach succeeded */
2725 result = dl_load_unload (cvptr, uptr, TRUE); /* then load the heads */
2726
2727 dl_set_timing (cvptr->device->units, /* reestablish */
2728 (cvptr->device->flags & DEV_REALTIME), /* the delay times */
2729 NULL, (void *) cvptr); /* pointer(s) */
2730
2731 return result; /* return the command result status */
2732 }
2733
2734
2735 /* Detach a disc image file from a unit.
2736
2737 The heads are unloaded on the drive, and the attached file, if any, is
2738 detached.
2739 */
2740
dl_detach(CVPTR cvptr,UNIT * uptr)2741 t_stat dl_detach (CVPTR cvptr, UNIT *uptr)
2742 {
2743 t_stat unload, detach;
2744
2745 unload = dl_load_unload (cvptr, uptr, FALSE); /* unload the heads */
2746
2747 if (unload == SCPE_OK || unload == SCPE_INCOMP) { /* if the unload succeeded */
2748 detach = detach_unit (uptr); /* then detach the unit */
2749
2750 if (detach == SCPE_OK) /* if the detach succeeded as well */
2751 return unload; /* then return the unload status */
2752 else /* otherwise */
2753 return detach; /* return the detach failure status */
2754 }
2755
2756 else /* otherwise the unload failed */
2757 return unload; /* so return the failure status */
2758 }
2759
2760
2761 /* Load or unload the drive heads.
2762
2763 In hardware, a drive's heads are loaded when a disc pack is installed and the
2764 RUN/STOP switch is set to RUN. The drive reports First Status when the heads
2765 load to indicate that the pack has potentially changed. Setting the switch
2766 to STOP unloads the heads. When the heads are unloaded, the drive reports
2767 Not Ready and Drive Busy status. In both cases, the drive reports Attention
2768 status to the controller. A MAC controller will clear a drive's Attention
2769 status and will interrupt the CPU when the drives are polled in the Idle
2770 Loop. An ICD controller also clears the drive's Attention status but will
2771 assert a Parallel Poll Response only when the heads unload.
2772
2773 In simulation, the unit must be attached, corresponding to having a disc pack
2774 installed in the drive, before the heads may be unloaded or loaded. If it
2775 isn't, the routine returns SCPE_UNATT. Otherwise, the UNIT_UNLOAD flag and
2776 the drive status are set accordingly.
2777
2778 If the (MAC) controller is idle, the routine returns SCPE_INCOMP to indicate
2779 that the caller must then call the controller to poll for drive attention to
2780 complete the command. Otherwise, it returns SCPE_OK, and the drives will be
2781 polled automatically when the current command or command wait completes and
2782 the controller is idled.
2783
2784
2785 Implementation notes:
2786
2787 1. Loading or unloading the heads clears Fault and Seek Check status.
2788
2789 2. If we are called during a RESTORE command, the unit's flags are not
2790 changed to avoid upsetting the state that was SAVEd.
2791
2792 3. Unloading an active unit does not cancel the event. This ensures that
2793 the controller will not hang during a transfer but instead will see the
2794 unloaded unit and fail the transfer with Access_Not_Ready status.
2795 */
2796
dl_load_unload(CVPTR cvptr,UNIT * uptr,t_bool load)2797 t_stat dl_load_unload (CVPTR cvptr, UNIT *uptr, t_bool load)
2798 {
2799 if ((uptr->flags & UNIT_ATT) == 0) /* the unit must be attached to [un]load */
2800 return SCPE_UNATT; /* so return "Unit not attached" if it is not */
2801
2802 else if ((sim_switches & SIM_SW_REST) == 0) { /* if we are not being called during a RESTORE command */
2803 uptr->STATUS &= ~S2_CPS; /* then do a "Controller Preset" on the unit */
2804
2805 if (load) { /* if we are loading the heads */
2806 uptr->flags &= ~UNIT_UNLOAD; /* then clear the unload flag */
2807 uptr->STATUS |= S2_FIRST_STATUS; /* and set First Status */
2808
2809 if (cvptr->type != ICD) /* if this is not an ICD controller */
2810 uptr->STATUS |= S2_ATTENTION; /* then set Attention status also */
2811 }
2812
2813 else { /* otherwise we are unloading the heads */
2814 uptr->flags |= UNIT_UNLOAD; /* so set the unload flag */
2815 uptr->STATUS |= S2_ATTENTION; /* and Attention status */
2816 }
2817
2818 tpprintf (cvptr->device, DL_DEB_CMD, "RUN/STOP switch set to %s\n",
2819 (load ? "RUN" : "STOP"));
2820
2821 if (cvptr->type == MAC && cvptr->state == Idle_State) /* if this is a MAC controller, and it's idle */
2822 return SCPE_INCOMP; /* then the controller must be called to poll the drives */
2823 } /* otherwise indicate that the command is complete */
2824
2825 return SCPE_OK; /* return normal completion status to the caller */
2826 }
2827
2828
2829 /* Set the drive model.
2830
2831 This validation routine is called to set the model of the disc drive
2832 associated with the specified unit. The "value" parameter indicates the
2833 model ID, and the unit capacity is set to the size indicated.
2834
2835
2836 Implementation notes:
2837
2838 1. If the drive is changed from a 7905 or 7906, which has separate head
2839 protect switches, to a 7920 or 7925, which has a single protect switch,
2840 ensure that both protect bits are set so that all heads are protected.
2841 */
2842
dl_set_model(UNIT * uptr,int32 value,char * cptr,void * desc)2843 t_stat dl_set_model (UNIT *uptr, int32 value, char *cptr, void *desc)
2844 {
2845 if (uptr->flags & UNIT_ATT) /* if the unit is currently attached */
2846 return SCPE_ALATT; /* then the disc model cannot be changed */
2847
2848 uptr->capac = drive_props [GET_MODEL (value)].words; /* set the capacity to the new value */
2849
2850 if (uptr->flags & UNIT_PROT /* if either protect bit is set */
2851 && (value == UNIT_7920 || value == UNIT_7925)) /* and the new drive is a 7920 or 7925 */
2852 uptr->flags |= UNIT_PROT; /* then ensure that both bits are set */
2853
2854 return SCPE_OK;
2855 }
2856
2857
2858 /* Set or clear the write protection status.
2859
2860 This validation routine is called to set the write protection status of the
2861 disc drive associated with the specified unit. The "value" parameter
2862 indicates whether the drive is to be protected (1) or unprotected (0).
2863
2864 In hardware, the 7920 and 7925 drives have a READ ONLY switch that write-
2865 protects all heads in the drive, and Read-Only status directly reflects the
2866 position of the switch. The switch is simulated by the SET <unit> PROTECT
2867 and SET <unit> UNPROTECT commands.
2868
2869 The 7905 and 7906 drives have separate PROTECT UPPER DISC and PROTECT LOWER
2870 DISC switches that protect heads 0-1 and 2 (7905) or 2-3 (7906),
2871 respectively, and Read-Only status reflects the position of the switch
2872 associated with the head currently addressed by the drive's Head Register.
2873 The Head Register is loaded by the controller as part of a Seek or Cold Load
2874 Read command, or during an auto-seek or spare track seek, if permitted by the
2875 file mask. A Controller Preset command sent to a drive clears the Head
2876 Register, so Read-Only status reflects the PROTECT UPPER DISC switch setting.
2877
2878 The SET <unit> PROTECT=(UPPER | LOWER) and SET <unit> UNPROTECT=(UPPER |
2879 LOWER) simulation commands are provided to protect or unprotect the upper or
2880 lower heads individually. If the option values are omitted, e.g., SET <unit>
2881 PROTECT, then both upper and lower heads are (un)protected.
2882 */
2883
dl_set_protect(UNIT * uptr,int32 value,char * cptr,void * desc)2884 t_stat dl_set_protect (UNIT *uptr, int32 value, char *cptr, void *desc)
2885 {
2886 const uint32 model = uptr->flags & UNIT_MODEL;
2887 char gbuf [CBUFSIZE];
2888
2889 if (cptr == NULL) /* if there are no arguments */
2890 if (value) /* then if setting the protection status */
2891 uptr->flags |= UNIT_PROT; /* then protect all heads */
2892 else /* otherwise */
2893 uptr->flags &= ~UNIT_PROT; /* unprotect all heads */
2894
2895 else if (*cptr == '\0') /* otherwise if the argument is empty */
2896 return SCPE_MISVAL; /* then reject the command */
2897
2898 else if (model == UNIT_7920 || model == UNIT_7925) /* otherwise if this is a 7920 or 7925 */
2899 return SCPE_ARG; /* then the heads cannot be protected separately */
2900
2901 else { /* otherwise a 7905/06 argument is present */
2902 cptr = get_glyph (cptr, gbuf, ';'); /* get the argument */
2903
2904 if (strcmp ("LOWER", gbuf) == 0) /* if the LOWER option was specified */
2905 if (value) /* then if setting the protection status */
2906 uptr->flags |= UNIT_PROT_L; /* then set the protect lower disc flag */
2907 else /* otherwise */
2908 uptr->flags &= ~UNIT_PROT_L; /* clear the protect lower disc flag */
2909
2910 else if (strcmp ("UPPER", gbuf) == 0) /* otherwise if the UPPER option was specified */
2911 if (value) /* then if setting the protection status */
2912 uptr->flags |= UNIT_PROT_U; /* then set the protect upper disc flag */
2913 else /* otherwise */
2914 uptr->flags &= ~UNIT_PROT_U; /* clear the protect upper disc flag */
2915
2916 else /* otherwise some other argument was given */
2917 return SCPE_ARG; /* so report the error */
2918 }
2919
2920 return SCPE_OK;
2921 }
2922
2923
2924 /* Show the write protection status.
2925
2926 This display routine is called to show the write protection status of the
2927 disc drive associated with the specified unit. The "value" and "desc"
2928 parameters are unused.
2929
2930 The unit flags contain two bits that indicate write protection for heads 0-1
2931 and heads 2-n. If both bits are clear, the drive is unprotected. A 7905 or
2932 7906 drive may have one or the other or both bits set, indicating that the
2933 upper, lower, or both platters are protected. A 7920 or 7925 will have both
2934 bits set, indicating that the entire drive is protected.
2935 */
2936
dl_show_protect(FILE * st,UNIT * uptr,int32 value,void * desc)2937 t_stat dl_show_protect (FILE *st, UNIT *uptr, int32 value, void *desc)
2938 {
2939 const uint32 model = uptr->flags & UNIT_MODEL;
2940
2941 if ((uptr->flags & UNIT_PROT) == 0) /* if the protection flags are clear */
2942 fputs ("unprotected", st); /* then report the disc as unprotected */
2943
2944 else if (model == UNIT_7905 || model == UNIT_7906) /* otherwise if this is a 7905/06 */
2945 if ((uptr->flags & UNIT_PROT) == UNIT_PROT_L) /* then if only the lower disc protect flag is set */
2946 fputs ("lower protected", st); /* then report it */
2947 else if ((uptr->flags & UNIT_PROT) == UNIT_PROT_U) /* otherwise if only the upper disc protect flag is set */
2948 fputs ("upper protected", st); /* then report it */
2949 else /* otherwise both flags are set */
2950 fputs ("lower/upper protected", st); /* so report them */
2951
2952 else /* otherwise it's a 7920/25 */
2953 fputs ("protected", st); /* so either flag set indicates a protected disc */
2954
2955 return SCPE_OK;
2956 }
2957
2958
2959 /* Set or clear the diagnostic override table.
2960
2961 This validation routine is called to set or clear the diagnostic override
2962 table associated with the specified unit. The "value" parameter is either
2963 the positive maximum table entry count if an entry is to be added, or zero if
2964 the table is to be cleared, and "desc" is a pointer to the controller.
2965
2966 If the CPU interface declares a diagnostic override table, it will specify
2967 the table when initializing the controller variables structure with the
2968 CNTLR_INIT macro. This sets the "dop_base" pointer in the structure to point
2969 at the table. If the interface does not declare a table, the pointer will be
2970 NULL.
2971
2972 If the table is present, new entries may be added with this command:
2973
2974 SET <dev> DIAG=<cylinder>;<head>;<sector>;<opcode>;<spd>;<status>
2975
2976 The cylinder, head, and sector values are entered as decimal numbers, the
2977 opcode and status values are entered as octal numbers, and the SPD value is
2978 specified as any combination of the letters "S", "P", or "D".
2979
2980 If a command specifies the opcode value as Request Syndrome (15) and the
2981 status value as Correctable Data Error (17), then four additional values must
2982 be specified as part of the command line above:
2983
2984 ;<displacement>;<syndrome 1>;<syndrome 2>;<syndrome 3>
2985
2986 The displacement value is entered as a decimal number, and the three syndrome
2987 values are entered as octal numbers.
2988
2989 Entering SET <dev> DIAG by itself resets the current entry pointer to the
2990 first table entry. Entering SET <dev> NODIAG clears the table.
2991
2992 If the override table was not declared by the CPU interface, the routine
2993 returns "Command not allowed." If SET NODIAG was entered, the "value"
2994 parameter will be -1, and the table will be cleared by storing the special
2995 value DL_OVEND into the first table entry. Otherwise, if SET DIAG is
2996 entered, the table pointer is reset. However, if the table is already empty,
2997 the routine returns "Missing value" to indicate that the table must be
2998 populated first.
2999
3000 If a new entry is to be added, the "value" parameter will indicate the size
3001 of the table in entries. If no free entry exists, the routine returns
3002 "Memory exhausted". Otherwise, the supplied parameters are parsed and
3003 entered into the table. An array of maximum allowed values and radixes are
3004 used during parsing to validate each parameter. The non-numeric SPD
3005 parameter is parsed separately. If, after parsing the first six parameters,
3006 the opcode and status are Request Syndrome and Correctable Data Error,
3007 respectively, then four more parameters are sought. These are stored into
3008 the following table entry.
3009
3010
3011 Implementation notes:
3012
3013 1. Each maximum array element value limits the absolute value of its
3014 corresponding numeric parameter. Negative values may be specified for
3015 unsigned values; no error is returned, and these simply will never match
3016 their intended controller values.
3017
3018 2. Each radix array element value is used to parse its corresponding
3019 parameter. A radix of 0 is used to indicate the S/P/D parameter, which
3020 is parsed alphabetically rather than numerically.
3021
3022 3. One table entry is always reserved for the end-of-table value, so the
3023 number of configurable entries is one less than the defined table size.
3024 */
3025
dl_set_diag(UNIT * uptr,int32 value,char * cptr,void * desc)3026 t_stat dl_set_diag (UNIT *uptr, int32 value, char *cptr, void *desc)
3027 {
3028 typedef struct {
3029 t_value max; /* maximum allowed value */
3030 uint32 radix; /* numeric parsing radix */
3031 } PARSER_PROP;
3032
3033 static const PARSER_PROP param [] = {
3034 /* maximum value radix */
3035 /* ------------- ----- */
3036 { 822, 10 }, /* cylinder */
3037 { 8, 10 }, /* head */
3038 { 63, 10 }, /* sector */
3039 { LAST_OPCODE, 8 }, /* opcode */
3040 { 0, 0 }, /* SPD */
3041 { LAST_STATUS, 8 }, /* status */
3042 { 135, 10 }, /* displacement */
3043 { D16_UMAX, 8 }, /* syndrome 1 */
3044 { D16_UMAX, 8 }, /* syndrome 2 */
3045 { D16_UMAX, 8 } /* syndrome 3 */
3046 };
3047
3048 const CVPTR cvptr = (CVPTR) desc;
3049 DIAG_ENTRY *entry;
3050 uint32 pidx, params [10];
3051 t_stat status;
3052 char gbuf [CBUFSIZE];
3053
3054 if (cvptr->dop_base == NULL) /* if the override array is not present */
3055 return SCPE_NOFNC; /* then the command is not allowed */
3056
3057 else if (value == 0) /* otherwise if this is a NODIAG call */
3058 if (cptr != NULL) /* then if something follows the keyword */
3059 return SCPE_2MARG; /* then report an error */
3060
3061 else { /* otherwise the command is valid */
3062 cvptr->dop_index = -1; /* so clear the current entry pointer */
3063 cvptr->dop_base->cylinder = DL_OVEND; /* and mark the first entry as the end */
3064 }
3065
3066 else if (cptr == NULL) /* otherwise if DIAG is by itself */
3067 if (cvptr->dop_base->cylinder == DL_OVEND) /* then if there are no entries in the table */
3068 return SCPE_MISVAL; /* then one must be entered first */
3069 else /* otherwise */
3070 cvptr->dop_index = 0; /* reset the current pointer to the first entry */
3071
3072 else if (*cptr == '\0') /* otherwise if there are no parameters */
3073 return SCPE_MISVAL; /* then report a missing value */
3074
3075 else { /* otherwise at least one parameter is present */
3076 for (entry = cvptr->dop_base; /* find the */
3077 entry->cylinder != DL_OVEND && value > 0; /* last entry */
3078 entry++, value--); /* in the current table */
3079
3080 if (value <= 1) /* if there's not enough room to add a new entry */
3081 return SCPE_MEM; /* then report the error to the user */
3082
3083 else { /* otherwise there's at least one free entry */
3084 for (pidx = 0; pidx < 10; pidx++) { /* so assume a full set of arguments are present */
3085 if (*cptr == '\0') /* if the next argument is not there */
3086 return SCPE_2FARG; /* then report it missing */
3087
3088 if (param [pidx].radix == 0) { /* if this is the SPD argument */
3089 params [pidx] = 0; /* then parse it specially */
3090
3091 while (*cptr != ';' && *cptr != '\0') { /* look for multiple arguments */
3092 if (*cptr == 'S') /* if it's an S */
3093 params [pidx] |= CM_SPARE; /* then set the spare bit */
3094 else if (*cptr == 'P') /* or if it's a P */
3095 params [pidx] |= CM_PROTECTED; /* then set the protected bit */
3096 else if (*cptr == 'D') /* or if it's a D */
3097 params [pidx] |= CM_DEFECTIVE; /* then set the defective bit */
3098 else /* any other character */
3099 return SCPE_ARG; /* results in an invalid argument error */
3100
3101 cptr++; /* point at the next character and continue */
3102 } /* until a separator or terminator is seen */
3103
3104 if (*cptr == ';') /* if a separator was seen */
3105 cptr++; /* then move past it */
3106
3107 status = SCPE_OK; /* reassure the compiler that status is not uninitialized */
3108 }
3109
3110 else { /* otherwise parse a numeric argument */
3111 cptr = get_glyph (cptr, gbuf, ';'); /* get the argument */
3112
3113 if (gbuf [0] == '-') { /* if the argument is negative */
3114 gbuf [0] = ' '; /* then clear the sign */
3115 params [pidx] = /* and negate the resulting value */
3116 (uint32) NEG16 (get_uint (gbuf, param [pidx].radix,
3117 param [pidx].max, &status));
3118 }
3119
3120 else /* otherwise the argument is unsigned */
3121 params [pidx] = /* so use the value as is */
3122 (uint32) get_uint (gbuf, param [pidx].radix,
3123 param [pidx].max, &status);
3124 }
3125
3126 if (status != SCPE_OK) /* if an error occurred */
3127 return status; /* then return the parsing status */
3128
3129 if (pidx == 5 /* if we have parsed the status */
3130 && (params [3] != Request_Syndrome /* and this is not a Request Syndrome entry */
3131 || params [5] != Correctable_Data_Error)) /* with Correctable Data Error status */
3132 break; /* then no more parameters are expected */
3133 }
3134
3135 if (*cptr != '\0') /* if more characters are present */
3136 return SCPE_2MARG; /* then report the excess */
3137
3138 else if (pidx == 10 && value <= 2) /* otherwise if we have syndrome values but no space */
3139 return SCPE_MEM; /* the report that we can't store them */
3140
3141 entry->cylinder = params [0]; /* store the */
3142 entry->head = params [1]; /* first set */
3143 entry->sector = params [2]; /* of parameter values */
3144 entry->opcode = (CNTLR_OPCODE) params [3]; /* in the */
3145 entry->spd = params [4]; /* first available */
3146 entry->status = (CNTLR_STATUS) params [5]; /* empty entry */
3147
3148 if (pidx == 10) { /* if syndrome values were present */
3149 entry++; /* then store them in the next available entry */
3150
3151 entry->spd = params [6]; /* save the displacement */
3152 entry->cylinder = params [7]; /* and the */
3153 entry->head = params [8]; /* three syndrome */
3154 entry->sector = params [9]; /* values */
3155 entry->opcode = Request_Syndrome; /* identify the entry */
3156 entry->status = Correctable_Data_Error; /* by opcode and status */
3157 }
3158
3159 entry++; /* point at the next available entry */
3160 entry->cylinder = DL_OVEND; /* and mark it as the end of the list */
3161
3162 cvptr->dop_index = 0; /* reset the current pointer to the start of the list */
3163 }
3164 }
3165
3166 return SCPE_OK;
3167 }
3168
3169
3170 /* Show the diagnostic override table.
3171
3172 This display routine is called to show the contents of the diagnostic
3173 override table. The "value" parameter is either the positive maximum table
3174 entry count if the routine was invoked by a SHOW <dev> DIAG command, or -1 if
3175 the routine was invoked by a SHOW <dev> command. The "desc" parameter is a
3176 pointer to the controller.
3177
3178 If the override table was not declared by the CPU interface, the routine
3179 returns "Command not allowed." Otherwise, if the table is empty, the routine
3180 prints "override disabled". If the table is populated, then the routine
3181 prints "override enabled" if it was invoked as part of a general SHOW for the
3182 device, or it prints the individual table entries if it was invoked as SHOW
3183 <dev> DIAG.
3184
3185 Entries are printed in tabular form with the columns corresponding to the SET
3186 DIAG parameters, except that the opcode and status fields are decoded. A
3187 Request Syndrome command entry with Correctable Data Error status is followed
3188 by an indented second line containing the displacement and syndrome values.
3189 Numeric values are printed in the same radix as is used to enter them.
3190
3191
3192 Implementation notes:
3193
3194 1. The Request Syndrome displacement parameter is a 16-bit signed value
3195 contained in a 32-bit unsigned array element. To print it properly, we
3196 convert the latter to a 16-bit signed value and then sign-extend to "int"
3197 size for fprintf.
3198
3199 2. The explicit use of "const CNTLR_VARS *" is necessary to declare a
3200 pointer to a constant structure. Using "const CVPTR" declares a constant
3201 pointer instead.
3202 */
3203
dl_show_diag(FILE * st,UNIT * uptr,int32 value,void * desc)3204 t_stat dl_show_diag (FILE *st, UNIT *uptr, int32 value, void *desc)
3205 {
3206 const CNTLR_VARS *cvptr = (const CNTLR_VARS *) desc; /* the controller pointer is supplied */
3207 DIAG_ENTRY *entry;
3208
3209 if (cvptr->dop_base == NULL) /* if the table isn't defined */
3210 return SCPE_NOFNC; /* then the command is illegal */
3211
3212 else if (cvptr->dop_index < 0) { /* otherwise if overrides are currently disabled */
3213 fputs ("override disabled", st); /* then report it */
3214
3215 if (value > 0) /* if we were invoked by a SHOW DIAG command */
3216 fputc ('\n', st); /* then we must add the line terminator */
3217 }
3218
3219 else if (value < 0) /* otherwise if we were invoked by a SHOW <dev> command */
3220 fputs ("override enabled", st); /* then print the table status instead of the details */
3221
3222 else for (entry = cvptr->dop_base; /* otherwise print each table entry */
3223 entry->cylinder != DL_OVEND && value > 0; /* until the end-of-table marker or count exhaustion */
3224 entry++, value--) {
3225 fprintf (st, "%3d %1d %2d %*s %c%c%c %*s\n", /* print the entry */
3226 entry->cylinder, entry->head, entry->sector,
3227 - OPCODE_LENGTH, dl_opcode_name (cvptr->type, entry->opcode),
3228 (entry->spd & CM_SPARE ? 'S' : ' '),
3229 (entry->spd & CM_PROTECTED ? 'P' : ' '),
3230 (entry->spd & CM_DEFECTIVE ? 'D' : ' '),
3231 - STATUS_LENGTH, dl_status_name (entry->status));
3232
3233 if (entry->opcode == Request_Syndrome /* if the current entry is a syndrome request */
3234 && entry->status == Correctable_Data_Error) { /* for a correctable data error */
3235 entry++; /* then the next entry contains the values */
3236 value = value - 1; /* drop the entry count to account for it */
3237
3238 fprintf (st, " %3d %06o %06o %06o\n", /* print the displacement and syndrome values */
3239 (int) INT16 (entry->spd),
3240 entry->cylinder, entry->head, entry->sector);
3241 }
3242 }
3243
3244 return SCPE_OK;
3245 }
3246
3247
3248 /* Set the controller timing mode.
3249
3250 This validation routine is called to set the timing mode for the disc
3251 subsystem. As this is an extended MTAB call, the "uptr" parameter points to
3252 the unit array of the device. The "value" parameter is set non-zero to use
3253 realistic timing and 0 to use fast timing. For a MAC controller, the "desc"
3254 parameter is a pointer to the controller. For ICD controllers, the "desc"
3255 parameter is a pointer to the first element of the controller array. There
3256 must be one controller for each unit defined by the device associated with
3257 the controllers. The "cptr" parameter is not used.
3258
3259 If fast timing is selected, the controller's timing pointer is set to the
3260 fast timing pointer supplied by the interface when the controller was
3261 initialized. If real timing is selected, the table of real times is searched
3262 for an entry whose controller type matches the supplied controller. MAC and
3263 ICD controllers support several drive models with identical timing
3264 characteristics. However, CS/80 controllers allow mixing drives with
3265 different timing on a single CPU interface. For these, the drive type must
3266 match as well. If a match is found, the controller's timing pointer is set
3267 to the associated real-time entry. Otherwise, the routine returns SCPE_IERR.
3268
3269 Non-MAC controllers are dedicated per-drive, so "desc" points not at a single
3270 controller instance but at an array of controller instances. The timing mode
3271 is common to every controller in the array.
3272 */
3273
dl_set_timing(UNIT * uptr,int32 value,char * cptr,void * desc)3274 t_stat dl_set_timing (UNIT *uptr, int32 value, char *cptr, void *desc)
3275 {
3276 CVPTR cvptr = (CVPTR) desc; /* the controller pointer is supplied */
3277 const DELAY_PROPS *dpptr;
3278 DRIVE_TYPE model;
3279 uint32 delay, cntlr_count;
3280
3281 if (cvptr->type == MAC) /* if this is a MAC controller */
3282 cntlr_count = 1; /* then there is one controller for all units */
3283 else /* otherwise */
3284 cntlr_count = cvptr->device->numunits; /* there is one controller per unit */
3285
3286 while (cntlr_count--) { /* set each controller's timing mode */
3287 if (value) { /* if realistic timing is requested */
3288 model = GET_MODEL (uptr->flags); /* then get the drive model from the current unit */
3289 dpptr = real_times; /* and reset the real-time delay table pointer */
3290
3291 for (delay = 0; delay < DELAY_COUNT; delay++) /* search for the correct set of times */
3292 if (dpptr->type == cvptr->type /* if the controller types match */
3293 && (dpptr->drive == HP_All /* and all drive times are the same */
3294 || dpptr->drive == model)) { /* or the drive types match as well */
3295 cvptr->dlyptr = dpptr; /* then use this set of times */
3296 break;
3297 }
3298 else /* otherwise */
3299 dpptr++; /* point at the next array element */
3300
3301 if (delay == DELAY_COUNT) /* if the model was not found in the table */
3302 return SCPE_IERR; /* then report an internal (impossible) error */
3303 else /* otherwise */
3304 cvptr->device->flags |= DEV_REALTIME; /* set the real time flag */
3305 }
3306
3307 else { /* otherwise fast timing is requested */
3308 cvptr->device->flags &= ~DEV_REALTIME; /* so clear the real time flag */
3309 cvptr->dlyptr = cvptr->fastptr; /* and set the delays to the FASTTIME settings */
3310 }
3311
3312 cvptr++; /* point at the next controller */
3313 uptr++; /* and corresponding unit for non-MAC controllers */
3314 }
3315
3316 return SCPE_OK;
3317 }
3318
3319
3320 /* Show the controller timing mode
3321
3322 This display routine is called to show the timing mode for the disc
3323 subsystem. The "value" parameter is unused; the "desc" parameter is a
3324 pointer to the controller.
3325
3326
3327 Implementation notes:
3328
3329 1. The explicit use of "const CNTLR_VARS *" is necessary to declare a
3330 pointer to a constant structure. Using "const CVPTR" declares a constant
3331 pointer instead.
3332 */
3333
dl_show_timing(FILE * st,UNIT * uptr,int32 value,void * desc)3334 t_stat dl_show_timing (FILE *st, UNIT *uptr, int32 value, void *desc)
3335 {
3336 const CNTLR_VARS *cvptr = (const CNTLR_VARS *) desc; /* the controller pointer is supplied */
3337
3338 if (cvptr->device->flags & DEV_REALTIME) /* if the real time flag is set */
3339 fputs ("realistic timing", st); /* then we're using realistic timing */
3340 else /* otherwise */
3341 fputs ("fast timing", st); /* we're using optimized timing */
3342
3343 return SCPE_OK;
3344 }
3345
3346
3347
3348 /* Disc library local controller routines */
3349
3350
3351 /* Start or stop the command/parameter wait timer.
3352
3353 A MAC controller uses a 1.74 second timer to ensure that it does not wait
3354 forever for a non-responding disc drive or CPU interface. In simulation, MAC
3355 interfaces supply an additional controller unit that is activated when the
3356 command or parameter wait timer is started and cancelled when the timer is
3357 stopped.
3358
3359 ICD interfaces do not use the wait timer or supply an additional unit.
3360
3361
3362 Implementation notes:
3363
3364 1. Absolute activation is used because the timer is restarted between
3365 parameter word transfers.
3366 */
3367
wait_timer(CVPTR cvptr,FLIP_FLOP action)3368 static void wait_timer (CVPTR cvptr, FLIP_FLOP action)
3369 {
3370 if (cvptr->type == MAC) /* if this a MAC controller */
3371 if (action == SET) /* then if the timer is to be set */
3372 sim_activate_abs (CNTLR_UPTR, CNTLR_TIMEOUT); /* then activate the controller unit */
3373
3374 else { /* otherwise the timer is to be stopped */
3375 sim_cancel (CNTLR_UPTR); /* so cancel the unit */
3376 CNTLR_UPTR->PHASE = Idle_Phase; /* and idle the controller unit */
3377 }
3378 return;
3379 }
3380
3381
3382 /* Idle the controller.
3383
3384 The command wait timer is turned off, the status is reset, and the controller
3385 is returned to the idle state (Poll Loop).
3386 */
3387
idle_controller(CVPTR cvptr)3388 static void idle_controller (CVPTR cvptr)
3389 {
3390 wait_timer (cvptr, CLEAR); /* stop the command wait timer */
3391
3392 cvptr->status = Normal_Completion; /* the Poll Loop clears the status */
3393 cvptr->state = Idle_State; /* idle the controller */
3394 return;
3395 }
3396
3397
3398 /* End the current command.
3399
3400 The currently executing command is completed with the supplied status. If
3401 the command completed normally, and it returns to the Poll Loop, the
3402 controller is idled, and the wait timer is cancelled. Otherwise, the
3403 controller enters the Wait Loop, and the wait timer is started. If the
3404 command had accessed a drive unit, the unit is idled. Also, for a MAC
3405 controller, the controller unit is idled as well.
3406 */
3407
end_command(CVPTR cvptr,UNIT * uptr,CNTLR_STATUS status)3408 static void end_command (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status)
3409 {
3410 cvptr->status = status; /* set the command result status */
3411
3412 if (status == Normal_Completion /* if the command completed normally */
3413 && cmd_props [cvptr->opcode].idle_at_end) { /* and this command idles the controller */
3414 cvptr->state = Idle_State; /* then set idle status */
3415 wait_timer (cvptr, CLEAR); /* and stop the command wait timer */
3416 }
3417
3418 else { /* otherwise */
3419 cvptr->state = Wait_State; /* the controller waits for a new command */
3420 wait_timer (cvptr, SET); /* so start the command wait timer */
3421
3422 if (uptr) /* if the command accessed a drive */
3423 uptr->PHASE = Idle_Phase; /* then idle it */
3424
3425 if (cvptr->type == MAC) /* if this is a MAC controller */
3426 CNTLR_UPTR->PHASE = Idle_Phase; /* then idle the controller unit as well */
3427 }
3428
3429 if (cmd_props [cvptr->opcode].transfer_size > 0)
3430 tpprintf (cvptr->device, DL_DEB_CMD, (cvptr->opcode == Initialize
3431 ? "Unit %u Initialize %s for %u words (%u sector%s)\n"
3432 : "Unit %u %s for %u words (%u sector%s)\n"),
3433 CM_UNIT (cvptr->spd_unit),
3434 (cvptr->opcode == Initialize
3435 ? fmt_bitset (cvptr->spd_unit, initialize_format)
3436 : opcode_name [cvptr->opcode]),
3437 cvptr->count,
3438 cvptr->count / cmd_props [cvptr->opcode].transfer_size + (cvptr->length > 0),
3439 (cvptr->count <= cmd_props [cvptr->opcode].transfer_size ? "" : "s"));
3440
3441 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command completed with %s status\n",
3442 CM_UNIT (cvptr->spd_unit), opcode_name [cvptr->opcode],
3443 dl_status_name (cvptr->status));
3444
3445 return;
3446 }
3447
3448
3449 /* Start a read operation on the current sector.
3450
3451 This routine is called at the end of the rotate phase to begin a read
3452 operation. The current sector given by the controller address is read from
3453 the disc image file into the sector buffer in preparation for data transfer
3454 to the CPU. If the end of the track had been reached, and the file mask
3455 permits, an auto-seek is scheduled instead to allow the read to continue.
3456 The routine returns TRUE if the data is ready to be transferred and FALSE if
3457 it is not (due to command completion, an error, or an auto-seek that must
3458 complete first).
3459
3460 On entry, the end-of-data flag is checked. If it is set, the current read
3461 command is completed. Otherwise, the buffer data offset and verify options
3462 are set up. For a Read Full Sector, the sync word is set from the controller
3463 type, and dummy cylinder and head-sector words are generated from the current
3464 location (as would be the case in the absence of track sparing).
3465
3466 The image file is positioned to the correct sector in preparation for
3467 reading. If the positioning requires a permitted seek, it is scheduled, and
3468 the routine returns with the Seek_Phase set to wait for seek completion
3469 before resuming the read (when the seek completes, the service routine will
3470 be entered, and we will be called again; this time, the end-of-cylinder flag
3471 will be clear and positioning will succeed). If positioning resulted in an
3472 error, the current read is terminated with the error status set.
3473
3474 If positioning succeeded within the same track, the sector image is read into
3475 the buffer at an offset determined by the operation (Read Full Sector leaves
3476 room at the start of the buffer for the sector header). If the image read
3477 failed with a host file system error, it is reported to the simulation
3478 console and the read ends with an Uncorrectable Data Error. If it succeeded
3479 but did not return a full sector, the remainder of the buffer is padded with
3480 zeros.
3481
3482 If the image was read correctly, the operation phase is set for the data
3483 transfer, the index of the first word to transfer is set, and the routine
3484 returns TRUE to begin the data transfer.
3485
3486
3487 Implementation notes:
3488
3489 1. This routine changes the unit phase state as follows:
3490
3491 Rotate_Phase => Idle_Phase if EOD or error (returns FALSE)
3492 Rotate_Phase => Seek_Phase if auto-seek (returns FALSE)
3493 Rotate_Phase => Data_Phase otherwise (returns TRUE)
3494
3495 2. The position_sector routine sets up the data phase if it succeeds or the
3496 seek phase if a seek is required.
3497 */
3498
start_read(CVPTR cvptr,UNIT * uptr,CNTLR_FLAG_SET flags)3499 static t_bool start_read (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags)
3500 {
3501 uint32 count, offset;
3502 const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OPCODE;
3503
3504 if (flags & EOD) { /* if the end of data is indicated */
3505 end_command (cvptr, uptr, Normal_Completion); /* then complete the command */
3506 return FALSE; /* and end the current operation */
3507 }
3508
3509 if (opcode == Read_Full_Sector) { /* if we are starting a Read Full Sector command */
3510 if (cvptr->type == MAC) /* then if this is a MAC controller */
3511 cvptr->buffer [0] = 0100376; /* indicate that ECC support is valid */
3512 else /* otherwise */
3513 cvptr->buffer [0] = 0100377; /* indicate that ECC support is not available */
3514
3515 set_address (cvptr, 1); /* set the current address into buffer words 1-2 */
3516 offset = 3; /* and start the data after the header */
3517 }
3518
3519 else /* otherwise it's a normal read command */
3520 offset = 0; /* so data starts at the beginning of the buffer */
3521
3522 if (position_sector (cvptr, uptr) == FALSE) /* position the sector; if it was not */
3523 return FALSE; /* then a seek is in progress or an error occurred */
3524
3525 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s from cylinder %u head %u sector %u\n",
3526 (int32) (uptr - cvptr->device->units), opcode_name [opcode],
3527 uptr->CYL, cvptr->head, cvptr->sector);
3528
3529 count = sim_fread (cvptr->buffer + offset, /* read the sector from the image */
3530 sizeof (DL_BUFFER), /* into the sector buffer */
3531 WORDS_PER_SECTOR, uptr->fileref);
3532
3533 if (ferror (uptr->fileref)) { /* if a host file system error occurred */
3534 io_error (cvptr, uptr, Uncorrectable_Data_Error); /* then report it to the simulation console */
3535 return FALSE; /* and terminate with Uncorrectable Data Error status */
3536 }
3537
3538 cvptr->length = cmd_props [opcode].transfer_size; /* set the appropriate transfer length */
3539 cvptr->index = 0; /* and reset the data index */
3540
3541 for (count = count + offset; count < cvptr->length; count++) /* pad the sector as needed */
3542 cvptr->buffer [count] = 0; /* e.g., if reading from a new file */
3543
3544 return TRUE; /* the read was successfully started */
3545 }
3546
3547
3548 /* Finish a read operation on the current sector.
3549
3550 This routine is called at the end of the intersector phase to finish a read
3551 operation. Command termination conditions are checked, and the next sector
3552 is addressed in preparation for the read to continue.
3553
3554 On entry, the diagnostic override status is checked. If it is set, then the
3555 read is terminated with the indicated status. Otherwise, the data overrun
3556 flag is checked. If it is set, the read is terminated with an error.
3557 Otherwise, the next sector is addressed.
3558
3559 If the end-of-data flag is set, the current read is completed. Otherwise,the
3560 rotate phase is set up in preparation for the next sector read.
3561
3562
3563 Implementation notes:
3564
3565 1. This routine changes the unit phase state as follows:
3566
3567 Intersector_Phase => Idle_Phase if EOD or error
3568 Intersector_Phase => Rotate_Phase otherwise
3569
3570 2. The HP 1000 CPU indicates the end of a read data transfer to an ICD
3571 controller by untalking the drive. The untalk is done by the driver as
3572 soon as the DCPC completion interrupt is processed. However, the time
3573 from the final DCPC transfer through driver entry to the point where the
3574 untalk is asserted on the bus varies from 80 instructions (RTE-6/VM with
3575 OS microcode and the buffer in the system map) to 152 instructions
3576 (RTE-IVB with the buffer in the user map). The untalk must occur before
3577 the start of the next sector, or the drive will begin the data transfer.
3578
3579 Normally, this is not a problem, as the driver clears the FIFO of any
3580 received data after DCPC completion. However, if the read terminates
3581 after the last sector of a track, and accessing the next sector would
3582 require an intervening seek, and the file mask disables auto-seeking or
3583 an enabled seek would move the positioner beyond the drive limits, then
3584 the controller will indicate an End of Cylinder error if the untalk does
3585 not arrive before the seek is initiated.
3586
3587 The RTE driver (DVA32) and various utilities that manage the disc
3588 directly (e.g., SWTCH) do not appear to account for these bogus errors,
3589 so the ICD controller hardware must avoid them in some unknown manner.
3590 We work around the issue by extending the intersector delay to allow time
3591 for a potential untalk whenever the next access would otherwise fail.
3592
3593 Note that this issue does not occur with writes because DCPC completion
3594 asserts EOI concurrently with the final data byte to terminate the
3595 command explicitly.
3596
3597 Note also that the delay is a fixed number of instructions, regardless of
3598 timing mode, to ensure that the CPU makes it through the driver code to
3599 output the untalk command.
3600 */
3601
end_read(CVPTR cvptr,UNIT * uptr,CNTLR_FLAG_SET flags)3602 static void end_read (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags)
3603 {
3604 uint32 bound;
3605
3606 if (cvptr->status != Normal_Completion) /* if a diagnostic override is present */
3607 end_command (cvptr, uptr, cvptr->status); /* then report the indicated status */
3608
3609 else if (flags & OVRUN) /* otherwise if a read overrun occurred */
3610 end_command (cvptr, uptr, Data_Overrun); /* then terminate the command with an error */
3611
3612 else { /* otherwise the read succeeded */
3613 next_sector (cvptr, uptr); /* so address the next sector */
3614
3615 if (flags & EOD) /* if the end of data is indicated */
3616 end_command (cvptr, uptr, Normal_Completion); /* then complete the command */
3617
3618 else { /* otherwise reading continues */
3619 uptr->PHASE = Rotate_Phase; /* so set up the unit for the rotate phase */
3620 uptr->wait = cvptr->dlyptr->intersector_gap; /* with a delay for the intersector time */
3621
3622 if (cvptr->eoc == SET && cvptr->type == ICD) { /* if a seek will be required on an ICD controller */
3623 if ((cvptr->file_mask & CM_AUTO_SEEK_EN) == 0) /* then if auto-seek is disabled */
3624 bound = cvptr->cylinder; /* then the bound is the current cylinder */
3625 else if (cvptr->file_mask & CM_DECR_SEEK) /* otherwise if a decremental seek is enabled */
3626 bound = 0; /* then the bound is cylinder 0 */
3627 else /* otherwise the enabled bound is the last cylinder */
3628 bound = drive_props [GET_MODEL (uptr->flags)].cylinders - 1;
3629
3630 if (cvptr->cylinder == bound) /* if the positioner is already at the bound */
3631 uptr->wait = UNTALK_DELAY; /* then the seek will fail; delay to allow CPU to untalk */
3632 }
3633 }
3634 }
3635
3636 return;
3637 }
3638
3639
3640 /* Start a write operation on the current sector.
3641
3642 This routine is called at the end of the rotate phase to begin a write
3643 operation. The current sector indicated by the controller address is
3644 positioned for writing from the sector buffer to the disc image file after
3645 data transfer from the CPU. If the end of the track had been reached, and
3646 the file mask permits, an auto-seek is scheduled instead to allow the write
3647 to continue. The routine returns TRUE if the data is ready to be
3648 transferred and FALSE if it is not (due to an error or an auto-seek that must
3649 complete first).
3650
3651 On entry, if writing is not permitted, or formatting is required but not
3652 enabled, the command is terminated with an error. Otherwise, the disc image
3653 file is positioned to the correct sector in preparation for writing.
3654
3655 If the positioning requires a permitted seek, it is scheduled, and the
3656 routine returns with the Seek_Phase set to wait for seek completion before
3657 resuming the write (when the seek completes, the service routine will be
3658 entered, and we will be called again; this time, the end-of-cylinder flag
3659 will be clear and positioning will succeed). If positioning resulted in an
3660 error, the current write is terminated with the error status set.
3661
3662 If positioning succeeded within the same track, the operation phase is set
3663 for the data transfer, the index of the first word to transfer is set, and
3664 the routine returns TRUE to begin the data transfer.
3665
3666
3667 Implementation notes:
3668
3669 1. This routine changes the unit phase state as follows:
3670
3671 Rotate_Phase => Idle_Phase if write protected or error (returns FALSE)
3672 Rotate_Phase => Seek_Phase if auto-seek (returns FALSE)
3673 Rotate_Phase => Data_Phase otherwise (returns TRUE)
3674
3675 2. The position_sector routine sets up the data phase if it succeeds or the
3676 seek phase if a seek is required.
3677 */
3678
start_write(CVPTR cvptr,UNIT * uptr)3679 static t_bool start_write (CVPTR cvptr, UNIT *uptr)
3680 {
3681 const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OPCODE;
3682
3683 if (opcode == Write /* if this is a Write command */
3684 && cvptr->spd_unit & CM_PROTECTED /* and the track is protected */
3685 && (uptr->flags & UNIT_FMT) == 0) /* but the FORMAT switch is not set */
3686 end_command (cvptr, uptr, Protected_Track); /* then fail with a protection error */
3687
3688 else if (uptr->STATUS & S2_READ_ONLY /* otherwise if the unit is write protected */
3689 || opcode != Write && (uptr->flags & UNIT_FMT) == 0) /* or the FORMAT switch must be set but is not */
3690 end_command (cvptr, uptr, Status_2_Error); /* then fail with a status error */
3691
3692 else if (position_sector (cvptr, uptr) == TRUE) { /* otherwise if positioning the sector succeeded */
3693 cvptr->length = cmd_props [opcode].transfer_size; /* then set the appropriate transfer length */
3694 cvptr->index = 0; /* and reset the data index */
3695
3696 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s to cylinder %u head %u sector %u\n",
3697 (int32) (uptr - cvptr->device->units), opcode_name [opcode],
3698 uptr->CYL, cvptr->head, cvptr->sector);
3699
3700 return TRUE; /* the write was successfully started */
3701 }
3702
3703 return FALSE; /* otherwise an error occurred or a seek is required */
3704 }
3705
3706
3707 /* Finish a write operation on the current sector.
3708
3709 This routine is called at the end of the intersector phase to finish a write
3710 operation. The current sector is written from the sector buffer to the disc
3711 image file at the current file position. The next sector address is then
3712 updated to allow writing to continue.
3713
3714 On entry, the drive is checked to ensure that it is ready for the write.
3715 Then the sector buffer is padded appropriately if a full sector of data was
3716 not transferred. The buffer is written to the disc image file at the
3717 position corresponding to the controller address as set when the sector was
3718 started. The write begins at a buffer offset determined by the command (a
3719 Write Full Sector has three header words at the start of the buffer that are
3720 not written to the disc image).
3721
3722 If the image write failed with a host file system error, it is reported to
3723 the simulation console and the write ends with an Uncorrectable Data Error.
3724 If it succeeded, the diagnostic override status is checked. If it is set,
3725 then the write is terminated with the indicated status. Otherwise, the data
3726 overrun flag is checked. If it is set, the write is terminated with an
3727 error. Otherwise, the next sector is addressed. If the end-of-data flag is
3728 set, the current write is completed. Otherwise,the rotate phase is set up in
3729 preparation for the next sector write.
3730
3731
3732 Implementation notes:
3733
3734 1. This routine changes the unit phase state as follows:
3735
3736 Intersector_Phase => Idle_Phase if EOD or error
3737 Intersector_Phase => Rotate_Phase otherwise
3738
3739 2. A partial sector is filled either with octal 177777 words (ICD) or copies
3740 of the last word (MAC), per page 7-10 of the ICD/MAC Disc Diagnostic
3741 manual.
3742 */
3743
end_write(CVPTR cvptr,UNIT * uptr,CNTLR_FLAG_SET flags)3744 static void end_write (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags)
3745 {
3746 uint32 count;
3747 DL_BUFFER pad;
3748 const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OPCODE;
3749 const uint32 offset = (opcode == Write_Full_Sector ? 3 : 0);
3750
3751 if (uptr->flags & UNIT_UNLOAD) { /* if the drive is not ready */
3752 end_command (cvptr, uptr, Access_Not_Ready); /* then terminate the command */
3753 return; /* with an access error */
3754 }
3755
3756 if (cvptr->index < WORDS_PER_SECTOR + offset) { /* if a partial sector was transferred */
3757 if (cvptr->type == ICD) /* then an ICD controller */
3758 pad = D16_UMAX; /* pads the sector with -1 words */
3759 else /* whereas a MAC controller */
3760 pad = cvptr->buffer [cvptr->index - 1]; /* pads with the last word written */
3761
3762 for (count = cvptr->index; count < WORDS_PER_SECTOR + offset; count++)
3763 cvptr->buffer [count] = pad; /* pad the sector buffer as needed */
3764 }
3765
3766 sim_fwrite (cvptr->buffer + offset, sizeof (DL_BUFFER), /* write the sector to the file */
3767 WORDS_PER_SECTOR, uptr->fileref);
3768
3769 if (ferror (uptr->fileref)) /* if a host file system error occurred, then report it */
3770 io_error (cvptr, uptr, Uncorrectable_Data_Error); /* and terminate with Uncorrectable Data Error status */
3771
3772 else if (cvptr->status != Normal_Completion) /* otherwise if a diagnostic override is present */
3773 end_command (cvptr, uptr, cvptr->status); /* then report the indicated status */
3774
3775 else if (flags & OVRUN) /* otherwise if a write overrun occurred */
3776 end_command (cvptr, uptr, Data_Overrun); /* then terminate the command with an error */
3777
3778 else { /* otherwise the write succeeded */
3779 next_sector (cvptr, uptr); /* so address the next sector */
3780
3781 if (flags & EOD) /* if the end of data is indicated */
3782 end_command (cvptr, uptr, Normal_Completion); /* then complete the command */
3783
3784 else { /* otherwise writing continues */
3785 uptr->PHASE = Rotate_Phase; /* so set up the unit for the rotate phase */
3786 uptr->wait = cvptr->dlyptr->intersector_gap; /* with a delay for the intersector time */
3787 }
3788 }
3789
3790 return;
3791 }
3792
3793
3794 /* Position the disc image file at the current sector.
3795
3796 The image file is positioned at the byte address corresponding to the drive's
3797 current cylinder and the controller's current head and sector addresses.
3798 Positioning may involve an auto-seek if a prior read or write addressed the
3799 final sector of a cylinder. If a seek is initiated or an error is detected,
3800 the routine returns FALSE to indicate that the positioning was not performed.
3801 If the file was positioned, the routine returns TRUE.
3802
3803 On entry, the diagnostic override status is checked. If it is set to
3804 anything other than a data error, then positioning is terminated with the
3805 indicated status to simulate an address verification failure. Otherwise, if
3806 the controller's end-of-cylinder flag is set, a prior read or write addressed
3807 the final sector in the current cylinder. If the file mask does not permit
3808 auto-seeking, the command is terminated with an End of Cylinder error.
3809 Otherwise, the cylinder is incremented or decremented as directed by the file
3810 mask, and a seek to the new cylinder is started.
3811
3812 If the increment or decrement resulted in an out-of-bounds value, the seek
3813 will return Seek Check status, and the command is terminated with an error.
3814 Otherwise, the seek is legal, and the routine returns with the seek phase set
3815 to wait for seek completion before resuming the current read or write. When
3816 the seek completes, the service routine will be entered, and we will be
3817 called again; this time, the end-of-cylinder flag will be clear and the read
3818 or write will continue on the new cylinder.
3819
3820 If the EOC flag was not set, the drive's position is checked against the
3821 controller's position if address verification is requested. If they are
3822 different, as may occur with an Address Record command that specified a
3823 different location than the last Seek command, a seek is started to the
3824 correct cylinder, and the routine returns with the unit set to the seek phase
3825 to wait for seek completion as above.
3826
3827 If the drive and controller positions agree or address verification is not
3828 requested, the CHS addresses are validated against the drive limits. If they
3829 are invalid, Seek Check status is set, and the command is terminated with an
3830 error.
3831
3832 If the addresses are valid, the drive is checked to ensure that it is ready
3833 for positioning. If it is, the file is positioned to a byte offset in the
3834 image file that is calculated from the CHS address. If positioning succeeds,
3835 the data phase is set up to begin the data transfer, and the routine returns
3836 TRUE to indicate that the file position is set. If positioning fails with a
3837 host file system error, it is reported to the simulation console, and the
3838 routine returns FALSE to indicate that an AGC (drive positioner) fault
3839 occurred.
3840
3841
3842 Implementation notes:
3843
3844 1. The ICD controller returns an End of Cylinder error if an auto-seek
3845 results in a position beyond the drive limits. The MAC controller
3846 returns a Status-2 error. Both controllers set the Seek Check bit in the
3847 drive status word.
3848 */
3849
position_sector(CVPTR cvptr,UNIT * uptr)3850 static t_bool position_sector (CVPTR cvptr, UNIT *uptr)
3851 {
3852 const DRIVE_TYPE model = GET_MODEL (uptr->flags); /* get the drive model */
3853
3854 if (cvptr->status != Normal_Completion /* if a diagnostic override is present */
3855 && cvptr->status != Uncorrectable_Data_Error /* and it's not */
3856 && cvptr->status != Correctable_Data_Error) /* a data error */
3857 end_command (cvptr, uptr, cvptr->status); /* then report it */
3858
3859 else if (cvptr->eoc == SET) /* otherwise if we are at the end of a cylinder */
3860 if (cvptr->file_mask & CM_AUTO_SEEK_EN) { /* then if an auto-seek is allowed */
3861 if (cvptr->file_mask & CM_DECR_SEEK) /* then if a decremental seek is requested */
3862 cvptr->cylinder = cvptr->cylinder - 1 & D16_MASK; /* then decrease the address with wraparound */
3863 else /* otherwise an incremental seek is requested */
3864 cvptr->cylinder = cvptr->cylinder + 1 & D16_MASK; /* so increase the address with wraparound */
3865
3866 start_seek (cvptr, uptr); /* start the auto-seek */
3867
3868 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s%s autoseek to cylinder %u head %u sector %u\n",
3869 (int32) (uptr - cvptr->device->units), opcode_name [uptr->OPCODE],
3870 (uptr->STATUS & S2_SEEK_CHECK ? " seek check on" : ""),
3871 cvptr->cylinder, cvptr->head, cvptr->sector);
3872
3873 if (uptr->STATUS & S2_SEEK_CHECK) /* if a seek check occurred */
3874 if (cvptr->type == ICD) /* then if this is an ICD controller */
3875 end_command (cvptr, uptr, End_of_Cylinder); /* then report it as an End of Cylinder error */
3876 else /* otherwise */
3877 end_command (cvptr, uptr, Status_2_Error); /* report it as a Status-2 error */
3878 }
3879
3880 else /* otherwise the file mask does not permit an auto-seek */
3881 end_command (cvptr, uptr, End_of_Cylinder); /* so terminate with an EOC error */
3882
3883 else if (cvptr->verify /* if address verification is enabled */
3884 && (uint32) uptr->CYL != cvptr->cylinder) { /* and the positioner is on the wrong cylinder */
3885 start_seek (cvptr, uptr); /* then start a seek to the correct cylinder */
3886
3887 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s%s reseek to cylinder %u head %u sector %u\n",
3888 (int32) (uptr - cvptr->device->units), opcode_name [uptr->OPCODE],
3889 (uptr->STATUS & S2_SEEK_CHECK ? " seek check on" : ""),
3890 cvptr->cylinder, cvptr->head, cvptr->sector);
3891
3892 if (uptr->STATUS & S2_SEEK_CHECK) /* if a seek check occurred */
3893 end_command (cvptr, uptr, Status_2_Error); /* then report a Status-2 error */
3894 }
3895
3896 else if (((uint32) uptr->CYL >= drive_props [model].cylinders) /* otherwise the heads are positioned correctly */
3897 || (cvptr->head >= drive_props [model].heads) /* but if the cylinder */
3898 || (cvptr->sector >= drive_props [model].sectors)) { /* or head or sector is out of bounds */
3899 uptr->STATUS |= S2_SEEK_CHECK; /* then set Seek Check status */
3900 end_command (cvptr, uptr, Status_2_Error); /* and terminate with an error */
3901 }
3902
3903 else if (uptr->flags & UNIT_UNLOAD) /* otherwise if the drive is not ready for positioning */
3904 end_command (cvptr, uptr, Access_Not_Ready); /* then terminate with an access error */
3905
3906 else { /* otherwise we are ready to move the heads */
3907 set_file_pos (cvptr, uptr, model); /* so calculate the new position */
3908
3909 if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) { /* set the image file position; if it failed */
3910 io_error (cvptr, uptr, Status_2_Error); /* then report it to the simulation console */
3911
3912 dl_load_unload (cvptr, uptr, FALSE); /* unload the heads */
3913 uptr->STATUS |= S2_FAULT; /* and set Fault status */
3914 }
3915
3916 else { /* otherwise the seek succeeded */
3917 uptr->PHASE = Data_Phase; /* so set up the data transfer phase */
3918
3919 if (cvptr->device->flags & DEV_REALTIME) /* if the real time mode is enabled */
3920 uptr->wait = cvptr->dlyptr->data_xfer /* then base the delay on the sector preamble size */
3921 * cmd_props [uptr->OPCODE].preamble_size;
3922 else /* otherwise */
3923 uptr->wait = cvptr->dlyptr->data_xfer; /* start the transfer with a nominal delay */
3924
3925 return TRUE; /* report that positioning was accomplished */
3926 }
3927 }
3928
3929 return FALSE; /* positioning failed or was deferred */
3930 }
3931
3932
3933 /* Address the next sector.
3934
3935 This routine is called after a sector has been successfully read or written
3936 in preparation for continuing the transfer. It is also called after the
3937 Request Syndrome command returns the correction status for a sector in error.
3938
3939 The controller's CHS address is incremented to point at the next sector. If
3940 the next sector number is valid, the routine returns. Otherwise, the sector
3941 number is reset to sector 0 and the address verification state is reset to
3942 enable it for a Read_Without_Verify command. If the file mask is set for
3943 cylinder mode, the head is incremented, and if the new head number is valid,
3944 the routine returns. If the head number is invalid, it is reset to head 0,
3945 and the end-of-cylinder flag is set. The EOC flag is also set if the file
3946 mask is set for surface mode.
3947
3948 The new cylinder address is not set here, because cylinder validation must
3949 only occur when the next sector is actually accessed. Otherwise, reading or
3950 writing the last sector on a track or cylinder with auto-seek disabled would
3951 cause an End of Cylinder error, even if the transfer ended with that sector.
3952 Instead, we set the EOC flag to indicate that a cylinder update is pending.
3953
3954 As a result of this deferred update method, the state of the EOC flag must be
3955 considered when returning the disc address to the CPU.
3956 */
3957
next_sector(CVPTR cvptr,UNIT * uptr)3958 static void next_sector (CVPTR cvptr, UNIT *uptr)
3959 {
3960 const DRIVE_TYPE model = GET_MODEL (uptr->flags); /* get the disc model */
3961
3962 cvptr->sector = cvptr->sector + 1; /* increment the sector number */
3963
3964 if (cvptr->sector < drive_props [model].sectors) /* if we at not the end of the track */
3965 return; /* then the next sector value is OK */
3966
3967 cvptr->sector = 0; /* otherwise wrap the sector number */
3968 cvptr->verify = cmd_props [uptr->OPCODE].verify_address; /* and set the address verification flag */
3969
3970 if (cvptr->file_mask & CM_CYL_MODE) { /* if the controller is in cylinder mode */
3971 cvptr->head = cvptr->head + 1; /* then increment the head */
3972
3973 if (cvptr->head < drive_props [model].heads) /* if we are not at the end of the cylinder */
3974 return; /* then the next head value is OK */
3975
3976 cvptr->head = 0; /* otherwise wrap the head number */
3977 }
3978
3979 cvptr->eoc = SET; /* set the end-of-cylinder flag */
3980 return; /* to indicate that an update is required */
3981 }
3982
3983
3984 /* Start a seek.
3985
3986 A seek is initiated on the indicated unit if the drive is ready and the
3987 cylinder, head, and sector values in the controller are valid for the current
3988 drive model. The routine returns TRUE if the unit is seeking and FALSE if
3989 the seek failed to start.
3990
3991 If the drive is not ready, the seek fails immediately with a Status-2 error.
3992 If the drive is already seeking, Seek Check status will occur, and the
3993 routine will return TRUE to allow the current seek to complete normally.
3994
3995 Otherwise, a seek is initiated to cylinder 0 if the current command is
3996 Recalibrate or to the cylinder value stored in the controller if it is not.
3997 EOC is reset for a seek but not for recalibrate, so that a reseek will return
3998 to the same location as was current when the recalibration was done.
3999
4000 If the controller cylinder is beyond the drive's limit, Seek Check status is
4001 set in the unit, and the heads are not moved. Otherwise, the relative
4002 cylinder position change is calculated, and the heads are moved to the new
4003 position.
4004
4005 If the controller head or sector is beyond the drive's limit, Seek Check
4006 status is set in the unit. Otherwise, Seek Check status is cleared.
4007
4008 In hardware, the controller issues tag bus SEEK and ADR (address record)
4009 commands to the drive to load the drive's cylinder, head, and sector
4010 registers. On the 7905 and 7906 drives, loading the head register
4011 establishes the drive's Read-Only status in conjunction with the PROTECT
4012 UPPER/LOWER DISC switch settings.
4013
4014 A seek check for either the cylinder, head, or sector terminates the current
4015 command for an ICD controller. For a MAC controller, the seek check is noted
4016 in the drive status, but processing will continue until the drive sets
4017 Attention status.
4018
4019 Finally, the unit is set to the seek phase, and the scheduling delay is
4020 calculated by the distance the heads traversed (in real time mode), or
4021 it is set to a fixed delay (in fast time mode).
4022
4023
4024 Implementation notes:
4025
4026 1. For ICD drives, a seek check will terminate the command immediately with
4027 a Status-2 error. A seek-in-progress seek check cannot occur on an ICD
4028 drive, however, because the second seek command will not be started until
4029 the first seek completes.
4030
4031 2. In hardware, a seek to the current location will set Drive Busy status
4032 for 1.3 milliseconds (the head settling time). In simulation, disc
4033 service is scheduled as though a one-cylinder seek was requested.
4034
4035 3. The head register contents does not affect Read-Only status on the 7920
4036 or 7925, which is established solely by the switch setting. However, we
4037 set the drive status here anyway as a convenience.
4038 */
4039
start_seek(CVPTR cvptr,UNIT * uptr)4040 static t_bool start_seek (CVPTR cvptr, UNIT *uptr)
4041 {
4042 int32 delta;
4043 uint32 target_cylinder;
4044 const DRIVE_TYPE model = GET_MODEL (uptr->flags); /* get the drive model */
4045
4046 if (uptr->flags & UNIT_UNLOAD) /* if the heads are unloaded */
4047 return FALSE; /* then the seek fails as the drive was not ready */
4048
4049 else if (uptr->PHASE == Seek_Phase) { /* otherwise if a seek is in progress */
4050 uptr->STATUS |= S2_SEEK_CHECK; /* then set Seek Check status */
4051 return TRUE; /* and return to let the seek complete */
4052 }
4053
4054 else if (uptr->OPCODE == Recalibrate) /* otherwise if the unit is recalibrating */
4055 target_cylinder = 0; /* then seek to cylinder 0 and don't reset the EOC flag */
4056
4057 else { /* otherwise it's a Seek command or an auto-seek request */
4058 target_cylinder = cvptr->cylinder; /* so seek to the controller cylinder */
4059 cvptr->eoc = CLEAR; /* and clear the end-of-cylinder flag */
4060 }
4061
4062 if (target_cylinder >= drive_props [model].cylinders) { /* if the cylinder is out of bounds */
4063 delta = 0; /* then don't change the positioner */
4064 uptr->STATUS |= S2_SEEK_CHECK; /* and set Seek Check status */
4065 }
4066
4067 else { /* otherwise the cylinder value is OK */
4068 delta = abs (uptr->CYL - (int32) target_cylinder); /* calculate the relative movement */
4069 uptr->CYL = target_cylinder; /* and move the positioner */
4070
4071 if (cvptr->head >= drive_props [model].heads /* if the head */
4072 || cvptr->sector >= drive_props [model].sectors) /* or the sector is out of bounds */
4073 uptr->STATUS |= S2_SEEK_CHECK; /* then set Seek Check status */
4074
4075 else { /* otherwise the head and sector are OK */
4076 uptr->STATUS &= ~S2_SEEK_CHECK; /* so clear Seek Check status */
4077
4078 if (uptr->flags & /* if the selected head is protected */
4079 (cvptr->head > 1 ? UNIT_PROT_L : UNIT_PROT_U))
4080 uptr->STATUS |= S2_READ_ONLY; /* then set read-only status */
4081 else /* otherwise */
4082 uptr->STATUS &= ~S2_READ_ONLY; /* clear it */
4083 }
4084 }
4085
4086 if (uptr->STATUS & S2_SEEK_CHECK && cvptr->type == ICD) /* if a seek check occurred on an ICD controller */
4087 return FALSE; /* then the command fails immediately */
4088
4089 else { /* otherwise the seek was OK or this is a MAC controller */
4090 uptr->PHASE = Seek_Phase; /* so set the unit to the seek phase */
4091
4092 uptr->wait = cvptr->dlyptr->seek_one /* set the seek delay, based on the relative movement */
4093 + delta * (cvptr->dlyptr->seek_full - cvptr->dlyptr->seek_one)
4094 / drive_props [model].cylinders;
4095 }
4096
4097 return TRUE; /* the seek is underway */
4098 }
4099
4100
4101 /* Report a stream I/O error.
4102
4103 Errors indicated by the host file system are printed on the simulation
4104 console, and the current command is terminated with the supplied status
4105 indication. The target OS will respond to the status return appropriately.
4106 */
4107
io_error(CVPTR cvptr,UNIT * uptr,CNTLR_STATUS status)4108 static void io_error (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status)
4109 {
4110 cprintf ("%s simulator disc library I/O error: %s\n", /* report the error to the console */
4111 sim_name, strerror (errno));
4112
4113 tpprintf (cvptr->device, cvptr->device->dctrl, "Host system stream I/O call failed: %s\n",
4114 strerror (errno));
4115
4116 clearerr (uptr->fileref); /* clear the error */
4117
4118 end_command (cvptr, uptr, status); /* terminate the command with the supplied status */
4119 return;
4120 }
4121
4122
4123 /* Set up the controller completion.
4124
4125 This routine performs a scheduled "end_command" to complete a command after a
4126 short delay. It is called for commands that execute to completion with no
4127 drive or CPU interface interaction. An otherwise unused "end phase" is
4128 scheduled just so that the command does not appear to complete
4129 instantaneously.
4130 */
4131
set_completion(CVPTR cvptr,UNIT * uptr,CNTLR_STATUS status)4132 static void set_completion (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status)
4133 {
4134 cvptr->status = status; /* save the supplied status */
4135 uptr->PHASE = End_Phase; /* schedule the end phase */
4136 uptr->wait = cvptr->dlyptr->overhead / 2; /* with a short delay */
4137 return;
4138 }
4139
4140
4141
4142 /* Disc library local utility routines */
4143
4144
4145 /* Set the current controller address into the buffer.
4146
4147 The controller's current cylinder, head, and sector are packed into two words
4148 and stored in the sector buffer, starting at the index specified. If the
4149 end-of-cylinder flag is set, the cylinder is incremented to reflect the
4150 auto-seek that will be attempted when the next sequential access is made.
4151
4152
4153 Implementation notes:
4154
4155 1. The 13037 firmware always increments the cylinder number if the EOC flag
4156 is set, rather than checking cylinder increment/decrement bit in the file
4157 mask.
4158 */
4159
set_address(CVPTR cvptr,uint32 index)4160 static void set_address (CVPTR cvptr, uint32 index)
4161 {
4162 cvptr->buffer [index] = /* update the cylinder if EOC is set */
4163 (DL_BUFFER) cvptr->cylinder + (cvptr->eoc == SET ? 1 : 0);
4164
4165 cvptr->buffer [index + 1] = /* merge the head and sector */
4166 (DL_BUFFER) (PO_HEAD (cvptr->head) | PO_SECTOR (cvptr->sector));
4167
4168 return;
4169 }
4170
4171
4172 /* Return the drive status (Status-2).
4173
4174 This routine returns the formatted unit status for the indicated drive unit.
4175
4176 In hardware, the controller outputs the Address Unit command on the drive tag
4177 bus and the unit number on the drive control bus. The addressed drive then
4178 responds by setting its internal "selected" flag. The controller then
4179 outputs the Request Status command on the tag bug, and the selected drive
4180 returns its status on the control bus. If a drive is selected but the heads
4181 are unloaded, the drive returns Not Ready and Busy status. If no drive is
4182 selected, the control bus floats inactive. This is interpreted by the
4183 controller as Not Ready status (because the drive returns an inactive Ready
4184 status).
4185
4186 In simulation, an enabled but detached unit corresponds to "selected but
4187 heads unloaded," and a disabled unit corresponds to a non-existent unit.
4188
4189
4190 Implementation notes:
4191
4192 1. The Attention, Read-Only, First Status, Fault, and Seek Check bits are
4193 stored in the unit status field. The other status bits are determined
4194 dynamically.
4195
4196 2. The Drive Busy bit is set if the unit is in the seek phase. In hardware,
4197 this bit indicates that the heads are not positioned over a track, i.e.,
4198 that a seek is in progress. A Request Status command is accepted only
4199 when the controller is waiting for seek completion or for a new command.
4200 Therefore, the unit will be either in the seek phase or the idle phase,
4201 respectively, when status is returned.
4202 */
4203
drive_status(UNIT * uptr)4204 static HP_WORD drive_status (UNIT *uptr)
4205 {
4206 HP_WORD status;
4207
4208 if (uptr == NULL) /* if the unit is invalid */
4209 return S2_ERROR | S2_NOT_READY; /* then it does not respond */
4210
4211 status = /* start with the drive type and unit status */
4212 S2_DRIVE_TYPE (GET_MODEL (uptr->flags)) | uptr->STATUS;
4213
4214 if (uptr->flags & UNIT_FMT) /* if the format switch is enabled */
4215 status |= S2_FORMAT_EN; /* then set the Format status bit */
4216
4217 if (uptr->flags & UNIT_DIS) /* if the unit does not exist */
4218 status |= S2_NOT_READY; /* then set the Not Ready bit */
4219
4220 else if (uptr->flags & UNIT_UNLOAD) /* if the heads are unloaded */
4221 status |= S2_NOT_READY | S2_BUSY; /* then set the Not Ready and Drive Busy bits */
4222
4223 if (uptr->PHASE == Seek_Phase) /* if a seek is in progress */
4224 status |= S2_BUSY; /* then set the Drive Busy bit */
4225
4226 if (status & S2_ERRORS) /* if there any Status-2 errors */
4227 status |= S2_ERROR; /* then set the Error summary bit */
4228
4229 return status; /* return the unit status */
4230 }
4231
4232
4233 /* Activate the unit.
4234
4235 The specified unit is activated using the unit's "wait" time. If tracing
4236 is enabled, the activation is logged to the debug file.
4237
4238
4239 Implementation notes:
4240
4241 1. The "%.0u" print specification in the trace call absorbs the zero "unit"
4242 value parameter without printing when the controller unit is specified.
4243 */
4244
activate_unit(CVPTR cvptr,UNIT * uptr)4245 static t_stat activate_unit (CVPTR cvptr, UNIT *uptr)
4246 {
4247 t_stat result;
4248 const int32 unit = (int32) (uptr - cvptr->device->units); /* the unit number */
4249
4250 tpprintf (cvptr->device, DL_DEB_SERV, (unit == CNTLR_UNIT
4251 ? "Controller unit%.0d %s %s phase delay %d service scheduled\n"
4252 : "Unit %d %s %s phase delay %d service scheduled\n"),
4253 (unit == CNTLR_UNIT ? 0 : unit), opcode_name [uptr->OPCODE],
4254 phase_name [uptr->PHASE], uptr->wait);
4255
4256 result = sim_activate (uptr, uptr->wait); /* activate the unit */
4257 uptr->wait = NO_EVENT; /* and reset the activation time */
4258
4259 return result; /* return the activation status */
4260 }
4261
4262
4263 /* Set up the rotation phase.
4264
4265 The supplied unit is set to the rotate phase at the start of a read or write
4266 command. In real time mode, the rotational latency is determined by the
4267 distance between the "current" sector location and the target sector
4268 location. The former is estimated from the current "simulation time," which
4269 is the number of event ticks since the simulation run was started, and the
4270 simulated disc rotation time, as follows:
4271
4272 (simulation_time / per_sector_time) MOD sectors_per_track
4273
4274 The distance is then:
4275
4276 (sectors_per_track + target_sector - current_sector) MOD sectors_per_track
4277
4278 ...and the latency is then:
4279
4280 distance * per_sector_time
4281
4282 In fast time mode, the latency is fixed at the specified per-sector time.
4283 */
4284
set_rotation(CVPTR cvptr,UNIT * uptr)4285 static void set_rotation (CVPTR cvptr, UNIT *uptr)
4286 {
4287 uint32 sectors_per_track;
4288 double distance;
4289
4290 uptr->PHASE = Rotate_Phase; /* set the phase */
4291
4292 if (cvptr->device->flags & DEV_REALTIME) { /* if the mode is real time */
4293 sectors_per_track = /* then calculate the latency as above */
4294 drive_props [GET_MODEL (uptr->flags)].sectors;
4295
4296 distance =
4297 fmod (sectors_per_track + cvptr->sector - CURRENT_SECTOR (cvptr, uptr),
4298 sectors_per_track);
4299
4300 uptr->wait = (int32) (cvptr->dlyptr->sector_full * distance);
4301 }
4302
4303 else /* otherwise the mode is fast time */
4304 uptr->wait = cvptr->dlyptr->sector_full; /* so use the specified time directly */
4305 }
4306
4307
4308 /* Set the image file position.
4309
4310 A cylinder/head/sector address is converted into a byte offset to pass to the
4311 host file I/O routines. The cylinder is supplied by the drive unit, and the
4312 head and sector addresses are supplied by the controller. The disc image
4313 file is laid out in one or two pieces, depending on whether a fixed platter
4314 is present in the drive. If it is, then the area corresponding to the
4315 removable platter precedes the area corresponding to the fixed platter. If
4316 not, then the file contains a single area encompassing all of the (removable)
4317 heads.
4318
4319 In either case, the target track within the area is:
4320
4321 cylinder * heads_per_cylinder + head
4322
4323 ...and the target byte position in the file is:
4324
4325 (target_track * sectors_per_track + sector) * bytes_per_sector
4326 */
4327
set_file_pos(CVPTR cvptr,UNIT * uptr,uint32 model)4328 static void set_file_pos (CVPTR cvptr, UNIT *uptr, uint32 model)
4329 {
4330 uint32 track;
4331
4332 if (cvptr->head < drive_props [model].remov_heads) /* if the head is on a removable platter */
4333 track = uptr->CYL * drive_props [model].remov_heads /* then the tracks in the file are contiguous */
4334 + cvptr->head;
4335
4336 else /* otherwise the head is on a fixed platter */
4337 track = drive_props [model].cylinders /* so the target track is located */
4338 * drive_props [model].remov_heads /* in the second area */
4339 + uptr->CYL * drive_props [model].fixed_heads /* that is offset from the first */
4340 + cvptr->head - drive_props [model].remov_heads; /* by the size of the removable platter */
4341
4342 uptr->pos = (track * drive_props [model].sectors + cvptr->sector) /* set the byte offset in the file */
4343 * WORDS_PER_SECTOR * sizeof (DL_BUFFER); /* of the CHS target sector */
4344
4345 return;
4346 }
4347