The following is a brief document about SWdriver (the switching driver) and its control. The driver intercept block is defined within the swdriver's sw_ucb structure. The following comments apply to its layout: /* The following area is the start of the intercept block needed for intercepts of driver entries. It has the following structure: Unique ID - generally the DPT address of the intercept driver, which will be unique for that driver on a given machine. Intercept DDT - the address of our interceptor's DDT. That is, if a second intercept occurs this cell should be filled in with a pointer to the interceptor's copy of the DDT, so this becomes a forward linked list outbound. If there is no intercept this should be null. Previous DDT - This cell holds a pointer to the DDT address as it was in the ucb$l_ddt of the intercepted driver before we intercepted the I/O and replaced the address with our own. This is an inbound list, singly linked. We use these two lists to permit intercepts to be added or removed. (Two lists are used here since the intercepted UCB in general has nowhere to keep a list head, though we need to be able to go either way.) ICsign - This cell holds a "magic number" which acts as a flag that the intercept we find is using the same scheme we are. This value is computed as hex F0070000 + DDT$K_LENGTH + 256*(length of the part of the intercept block that precedes the DDT copy). Thus it is sensitive to the amount of "stuff" preceding the DDT copy and to the DDT length. Flags 1 - Longword of flags. Only ones defined are fi8ok and nofipl8, to flag whether IPL8 postprocessing could be used with the intercept code of this intercept and all prior ones. Flags 2 - Spare longword of flags Userfiller[8] - 8 more longwords, reserved for any third parties who might need or want to keep extra information in their intercept blocks DDT - Copy of the intercepted driver's DDT, edited to point to whatever code is inserted first. The theory is that code wanting to continue with the intercepted code original function can follow the back link and use that to call the original DDT functions. Note too that the DDT contains an FDT pointer and several more, and that by inserting a copy of the original FDT with edits it is possible in like manner to chain FDT intercepts. At the end of an inserted FDT bit of code, one would locate and call the previous FDT table's routne. The presumption is also that intercepts are added by grabbing the intercepted driver's UCB$L_DDT pointer and that intercepts generally do not know of other intercepts' existence, save that when locating their intercept UCBs (or other data structures; the intercept blocks don't have to be inside UCBs) they check that the one they pick has the correct driver DPT address. Thus their intercepts would be called first, so that "inner" pointers grabbed at any stage will be valid. (That is, pointers to "previous" routine addresses grabbed by an intercept driver.) The following applies to the control program and operations to control operation of the switching driver: /* Model more or less after macro32 swctl. (Note because of cloned UCBs we must try to assign SWAn: first, then SWA0: and clone a unit if none found. If so, report the unit assigned in a message, a symbol, and a system logical. Use these logicals to keep track of disks assigned also. It's a convenient place to keep the information for use by the rest of the system.) Also look for a preexisting server when we do any call and ensure it is known to the SW units if present. Another logical can keep track of the server mailbox and pid. In the following, SWAn: can be SWA0:, the template unit if a specific unit is not given. In /report we really don't need the SW unit particularly; we do however need the disk name. This is however a piece of test code and a manual override for SWCTL /setup SWAn: disk: ! set up and add first path /add SWAn: disk: ! add another disk /deassign SWAn: disk: ! Deassign all disks, remove intercept /report SWAn: disk: ! return stats on paths /switch SWAn: pathnum ! switch to pathnum if disk is idle /idle SWAn: ! make the current disk go idle (so we can ! force a path switch) /unidle SWAn: ! undoes /idle, restarts I/O on a disk path /hook SWAn: ! "hook" the server (found by a logical) ! to the SWAn: unit provided its IPID and ! mailbox can be found /unhook SWAn: ! Unhook a server from SWAn: if any is hooked /second ! Use "2p" alias for the device, not the ! device itself, so we can use with cases ! of dk-du scsi<->mscp failover. If no function is present, ignore the command and junk it. A logical present would hold the server name and the server mailbox name. SWITCH$SERVER_MAILBOX and SWITCH$SERVER_PROCESS seem as good as any for names. Require them to be in exec mode or higher to keep folks from playing... Not all these functions will be done here at once, just enough to try some tests. The rest can be done at need. Buffer formats: ufunc uswitch lo uswitch hi ulen rest 1 dvc name len dvc name bash 2 dvc name len dvc name unbash 3 unit to sw to idlfgs=0 switch, err if dvc bsy 3 " idlfgs=1 save next irp, busy dvc 3 " idlfgs=2 restart i/o, unbusying dvc, no switch 4 unit to rpt ? statblk len statblk data rpt stats 5 ucb of dvc Report whether a device has a sw ucb intercepting it by returning its unit no, ucb, path blocks, etc. if present, 0 if none. 6 server ipid mbx nm len mbx name store server's mbx & ipid for swdriver] unit to talk to it 7 ... Clear swever info from a sw unit 8 ... Return octal 14747 (6631 decimal) if device is really a SW unit. Use for a sanity check. 9 UCB of device bash 10 UCB of device unbash Note too that the DDTAB entry ddt$ps_mntver_2 contains a pointer to an alternate entry (meant to be called from fork) which takes the exact same buffer args as above. Its call sequence is int swsetup(char* buffer, int bufsiz, UCB* swucb) where swucb is the UCB address of the SW device UCB and the buffer and buffer size are what would otherwise be passed as P1 and P2 in a $qio. Under ufunc 3, note, idflgs values 0 or 2 do nothing in this routine. Status returns directly from the call. Note Further: When doing a SETUP, a symbol SWCTL_SETUP_DVC will be set up to the value of the last generated SW device so that it won't be necessary for command procedures to try and figure it out externally. The DCL symbol SW_DEVICE will be set to the value of the SW device selected when a SWCTL/setup is done successfully. By using this symbol for subsequent SWCTL/add commands it will be possible to set up sets of devices easily.