Here's what we know about floppy prefixing support for HFS. Investigation was
halted Oct 18, 1988 in order to get model 360/370 support out quickly.

The problem is twofold:

1) if there is a non-HFS unit entry for a disk (typically only happens on
   floppies), in addition to an HFS entry on the same floppy, when the first 
   I/O to the floppy after changing media is not through HFS, the cache entries 
   for the HFS units on the floppy don't get invalidated. We could do this 
   to demonstrate the problem, before "fixing" it in released 3.2:
   
   put an HFS floppy in #43
   List it
   pop it and put in a different HFS floppy
   do a Volumes list
   list #43.

   You will see the listing from the first floppy, and not the currently
   inserted one. This is because Volumes calls the LIF DAM on #3 for 
   getvolumename before it calls HFSDAM on #43. The tm call by LIF consumes 
   the "media changed" status in the controller, clearing it, so hfstm never 
   sees it, and never clears the cache or pops the prefix to root.

2) To fix this, we tried invalidating cache and popping prefixes on all HFS 
   units for the base_unum whenever we saw umediavalid go false for the unit. 
   This is reliable for solving the problem, but is overkill: umediavalid is 
   set false often by the system or other code (see m68KSYS) for reasons 
   unrelated to media changes. The prefix would often go back to root for no 
   apparent reason.
   The extra cache invalidation reduced performance a small amount, but was
   not a problem.

We fixed the prefix popping problem in 3.2 by not allowing HFS
floppies to be prefixed below their roots. Relaxing this restriction is
the purpose of this investigation.

The fix must achieve the following:

1) the cache entries for any base_unum must be invalidated if floppy medium 
   has been replaced by another medium since loading cache.

2) prefix must be popped to the root for all HFS units on the floppy in the 
   above circumstance

3) prefix should not be popped unless the medium has changed or the device is 
   found to be unusable.

To achieve this we decided to do the following:

1) Put a routine into the unitable tm of each non-HFS floppy that would
   flush cache and pop prefix for all HFS units sharing the medium, if the 
   real tm (saved in the h_unitable tm) returned not umediavalid. This
   routine works by calling the "real" tm with the request it receives, then
   checking to see if umediavalid came back false; if so, it tells the HFS
   cacher to invalidate all entries for the base_unum of the unit, and pops
   all prefixes on HFSs with that base_unum. 
   The routine chosen was hfstm, as it knows about caching, and requires only 
   minor changes to do this. CTABLE (TABLE) is responsible for installing
   hfstm on non-HFS floppies, and creating consistent unitable and h_unitable
   entries for the unit. (files CTABLE and hfstm)

2) Remove code other than the above that flushes cache on umediavalid. (? 
   Haven't yet identified all these.)

3) Allow prefixing down HFS floppies. (file hfsdam)


Files expected to be affected:

----------------------------------------------------------------------------
CTABLE - modify set_base_unums somewhat as below (haven't compiled this):

procedure set_base_unums;
var i,j:unitnum;
begin		{tbl[j].base_unum was set to j in init_support in hfsupport}
  if h_unitable<>nil then with h_unitable^ do
    for i:=1 to maxunit do
      for j:=i+1 to maxunit do
        if     (tbl[j].base_unum=j)            {first time to modify this entry}
           and on_same_medium(i,j) then        {they are "synonym" units}
             begin
               if   ((not tbl[j].is_hfsunit) and (tbl[i].is_hfsunit))
                 or (tbl[j].is_hfsunit)  then
                 begin
                  tbl[j].base_unum:=i;
                  if (not unitable^[j].uisfixed) and 
		     (not tbl[j].is_hfsunit) then
                    begin
		      tbl[j].tm:=unitable^[j].tm;
                      unitable^[j].tm:=value(HFS_TM_NAME); {pseudo-code}
		    end;
                 end;
	     end;
end;

This ensures that LIF and HFS units on the same medium share the same
base_unum in h_unitable, regardless their relative unit numbers (eg 43 = LIF,
3=HFS had base_unum for 43=43, and base_unum for 3=3 before this fix). It
also installs hfstm in unitable for non-HFS floppy units, and moves the
"real" tm for these out to the h_unitable.

This can't be done in the tea procedure, as the secondary unit may not
be assigned yet.

Since set_base_unums is called by assign_temp_unitable, and no entries are
created after this except by cloning (extra_HFS-unit), this should be adequate.
Double-check.

----------------------------------------------------------------------------
hfstm - modify as follows

[... elided]
procedure hfstm(fp : fibp; request : amrequesttype;
		anyvar buffer : window; bufsize, position : integer);
[...]

var I_am_not_HFS:boolean;	{new}

[...]
{-----------------------------------}
begin {hfstm}
    old_tm := h_unitable^.tbl[fp^.funit].tm;

    case request of
	readbytes, startread:
	    begin
		reading := true;
		writing := false;
	    end;
	writebytes, startwrite:
	    begin
		reading := false;
		writing := true;
	    end;
	otherwise
	    begin
		reading := false;
		writing := false;
	    end;
    end;
    {
    { some requests go straight to original tm
    }
    I_am_not_HFS:=not h_unitable^.tbl[fp^.funit].is_hfs;	{new}
    
    if (not reading and not writing)
    or I_am_not_HFS						{new}
    or (fp^.pathid = raw_inode)
    or (bufsize = 0) then begin
	call(old_tm, fp, request,
		      buffer, bufsize, position);
	{should the check below be done even for HFS units? What happens if
	 the I/O fails? When does cache get invalidated and prefix popped?}
	if I_am_not_HFS and (not unitable^[fp^.funit].umediavalid) then {new}
	  begin
	    invalidate_unit(fp^.funit);	{my base_unum is correct due to 
					 TABLE changes in set_base_unums. new}
|	    fs:=get_superblock(fp^.funit); {prep for following media_gone.}
|	    if fs<>NIL then
|	      media_gone;		{"pop" prefixes on all related HFS.}
[alternative to stuff behind vertical bars, faster, less disruptive]
|	    with h_unitable^ do
|		for i:=1 to maxunit do
|		  if tbl[i].is_hfsunit and 
|		    (tbl[i].base_unum=tbl[fp^.funit).base_unum) then
|		    tbl[i].prefix:=2 {"pop" to root prefix}; 
	  end;							{new}
        goto 999;
    end;
[...]

Note that we leave umediavalid as we found it after invalidating/popping
prefixes for related HFS units. This way callers see exactly the same
relevant side effects from the TM as they did before intrusion of hfstm.

----------------------------------------------------------------------------
hfsdam - remove prevention of floppy prefixing as follows:

[...]

program hfs_dam_init(input, output);

[...]

procedure dosetunitprefix;
label 999;
var
    acatentry: catentry;
    dir_ip: inode_ptr_type;
    oldior: integer;    {for "protecting" ioresult during cleanup. SFB}
begin
[remove lines preceded by "|"]
|    {Added code to disable prefixing on floppies. Need to do this to prevent
|     "unreliable prefixing" caused by having dogetvolumename check umediavalid
|     and popping prefix if it's false. The trouble is that various pieces of code
|     (eg CI) clear umediavalid, even when the floppy has not been popped. SFB}

    dir_ip := nil;
    doopendirectory(acatentry, false);
    if ioresult = ord(inoerror) then begin
	if f.ftitle = '' then begin
	    dir_ip := get_inode(f.pathid);
	    if permission(dir_ip, x_permission) then
|	      {stymie attempt to prefix floppy below its root. SFB}
|	      if (not unitable^[unum].uisfixed) and (f.pathid <> root_inode) then
|	       begin
|		ioresult:=ord(ibadrequest);
|		goto 999;
|	       end
|	      else
	       begin
		h_unitable^.tbl[unum].prefix := f.pathid;
		unitable^[unum].uvid := acatentry.cname;
	    end;
	    
[...]

----------------------------------------------------------------------------
NOTE:  there are at least two instances in the 3.2 version where after
completing a "real" tm call, hfstm does not check success.  Although
results propagate out to caller via ioresult, hfstm does not take
advantage of the chance to invalidate the cache and pop prefixes.  These
cases are mostly unlikely events, such as an I/O failing after a
successful I/O, or a non-data-transfer I/O failing (when not reading and
not writing), so may not show up often.
