head     56.4;
access   paws bayes jws quist brad dew jwh;
symbols  ;
locks    ; strict;
comment  @# @;


56.4
date     93.07.06.11.08.35;  author jwh;  state Exp;
branches ;
next     56.3;

56.3
date     93.01.27.13.17.12;  author jwh;  state Exp;
branches ;
next     56.2;

56.2
date     93.01.27.11.58.35;  author jwh;  state Exp;
branches ;
next     56.1;

56.1
date     91.11.05.09.54.16;  author jwh;  state Exp;
branches ;
next     55.1;

55.1
date     91.08.25.10.29.41;  author jwh;  state Exp;
branches ;
next     54.3;

54.3
date     91.08.21.10.33.50;  author jwh;  state Exp;
branches ;
next     54.2;

54.2
date     91.08.21.09.38.34;  author jwh;  state Exp;
branches ;
next     54.1;

54.1
date     91.03.18.15.31.45;  author jwh;  state Exp;
branches ;
next     53.2;

53.2
date     91.03.15.15.24.52;  author jwh;  state Exp;
branches ;
next     53.1;

53.1
date     91.03.11.19.31.39;  author jwh;  state Exp;
branches ;
next     52.1;

52.1
date     91.02.19.09.16.14;  author jwh;  state Exp;
branches ;
next     51.1;

51.1
date     91.01.30.16.15.47;  author jwh;  state Exp;
branches ;
next     50.1;

50.1
date     90.10.29.16.30.19;  author jwh;  state Exp;
branches ;
next     49.1;

49.1
date     90.08.14.14.14.07;  author jwh;  state Exp;
branches ;
next     48.1;

48.1
date     90.07.26.11.20.25;  author jwh;  state Exp;
branches ;
next     47.1;

47.1
date     90.05.14.11.04.50;  author dew;  state Exp;
branches ;
next     46.1;

46.1
date     90.05.07.08.51.52;  author jwh;  state Exp;
branches ;
next     45.1;

45.1
date     90.04.19.15.59.48;  author jwh;  state Exp;
branches ;
next     44.2;

44.2
date     90.04.04.11.14.06;  author jwh;  state Exp;
branches ;
next     44.1;

44.1
date     90.04.01.22.16.55;  author jwh;  state Exp;
branches ;
next     43.1;

43.1
date     90.03.20.14.09.23;  author jwh;  state Exp;
branches ;
next     42.3;

42.3
date     90.02.22.16.43.55;  author dew;  state Exp;
branches ;
next     42.2;

42.2
date     90.02.06.12.37.56;  author dew;  state Exp;
branches ;
next     42.1;

42.1
date     90.01.23.17.53.43;  author jwh;  state Exp;
branches ;
next     41.3;

41.3
date     90.01.18.11.17.47;  author dew;  state Exp;
branches ;
next     41.2;

41.2
date     90.01.05.10.11.46;  author dew;  state Exp;
branches ;
next     41.1;

41.1
date     89.12.22.11.35.58;  author jwh;  state Exp;
branches ;
next     40.4;

40.4
date     89.12.14.15.43.55;  author dew;  state Exp;
branches ;
next     40.3;

40.3
date     89.10.31.13.59.05;  author dew;  state Exp;
branches ;
next     40.2;

40.2
date     89.10.24.14.16.04;  author dew;  state Exp;
branches ;
next     40.1;

40.1
date     89.09.29.11.57.13;  author jwh;  state Exp;
branches ;
next     39.2;

39.2
date     89.09.27.08.26.35;  author jwh;  state Exp;
branches ;
next     39.1;

39.1
date     89.09.26.16.41.57;  author dew;  state Exp;
branches ;
next     38.2;

38.2
date     89.09.14.16.45.36;  author dew;  state Exp;
branches ;
next     38.1;

38.1
date     89.08.29.11.33.52;  author jwh;  state Exp;
branches ;
next     37.1;

37.1
date     89.05.12.11.47.35;  author dew;  state Exp;
branches ;
next     36.2;

36.2
date     89.05.08.13.34.22;  author bayes;  state Exp;
branches ;
next     36.1;

36.1
date     89.02.06.10.25.17;  author dew;  state Exp;
branches ;
next     35.1;

35.1
date     89.02.02.13.40.37;  author dew;  state Exp;
branches ;
next     34.1;

34.1
date     89.01.23.16.15.51;  author jwh;  state Exp;
branches ;
next     33.1;

33.1
date     89.01.16.11.47.26;  author dew;  state Exp;
branches ;
next     32.1;

32.1
date     89.01.10.11.56.25;  author bayes;  state Exp;
branches ;
next     31.1;

31.1
date     88.12.14.18.17.27;  author bayes;  state Exp;
branches ;
next     30.1;

30.1
date     88.12.09.13.54.29;  author dew;  state Exp;
branches ;
next     29.1;

29.1
date     88.10.31.15.39.08;  author bayes;  state Exp;
branches ;
next     28.1;

28.1
date     88.10.06.11.05.24;  author dew;  state Exp;
branches ;
next     27.1;

27.1
date     88.09.29.11.48.05;  author bayes;  state Exp;
branches ;
next     26.1;

26.1
date     88.09.28.13.29.25;  author bayes;  state Exp;
branches ;
next     25.1;

25.1
date     88.03.02.09.41.26;  author bayes;  state Exp;
branches ;
next     24.1;

24.1
date     87.08.31.10.10.20;  author jws;  state Exp;
branches ;
next     23.1;

23.1
date     87.08.26.10.52.42;  author bayes;  state Exp;
branches ;
next     22.1;

22.1
date     87.08.17.11.34.45;  author bayes;  state Exp;
branches ;
next     21.1;

21.1
date     87.08.12.14.18.39;  author bayes;  state Exp;
branches ;
next     20.1;

20.1
date     87.07.30.11.30.28;  author bayes;  state Exp;
branches ;
next     19.3;

19.3
date     87.06.24.14.00.31;  author larry;  state Exp;
branches ;
next     19.2;

19.2
date     87.06.16.09.48.50;  author jws;  state Exp;
branches ;
next     19.1;

19.1
date     87.06.01.08.43.00;  author jws;  state Exp;
branches ;
next     18.1;

18.1
date     87.05.20.15.48.43;  author bayes;  state Exp;
branches ;
next     17.1;

17.1
date     87.04.30.10.54.34;  author jws;  state Exp;
branches ;
next     16.1;

16.1
date     87.04.26.16.05.13;  author jws;  state Exp;
branches ;
next     15.2;

15.2
date     87.04.21.13.37.41;  author bayes;  state Exp;
branches ;
next     15.1;

15.1
date     87.04.13.09.44.33;  author jws;  state Exp;
branches ;
next     14.2;

14.2
date     87.04.09.15.51.16;  author bayes;  state Exp;
branches ;
next     14.1;

14.1
date     87.04.01.15.52.56;  author jws;  state Exp;
branches ;
next     13.2;

13.2
date     87.03.30.11.13.46;  author jws;  state Exp;
branches ;
next     13.1;

13.1
date     87.02.28.18.48.44;  author jws;  state Exp;
branches ;
next     12.1;

12.1
date     87.02.02.13.41.13;  author jws;  state Exp;
branches ;
next     11.4;

11.4
date     87.01.27.14.34.49;  author jws;  state Exp;
branches ;
next     11.3;

11.3
date     87.01.27.14.23.36;  author jws;  state Exp;
branches ;
next     11.2;

11.2
date     87.01.27.14.03.49;  author jws;  state Exp;
branches ;
next     11.1;

11.1
date     87.01.19.10.07.55;  author jws;  state Exp;
branches ;
next     10.1;

10.1
date     86.12.24.11.22.31;  author jws;  state Exp;
branches ;
next     9.4;

9.4
date     86.12.16.13.08.40;  author jws;  state Exp;
branches ;
next     9.3;

9.3
date     86.12.16.10.22.12;  author jws;  state Exp;
branches ;
next     9.2;

9.2
date     86.12.16.10.18.04;  author jws;  state Exp;
branches ;
next     9.1;

9.1
date     86.12.12.15.05.13;  author bayes;  state Exp;
branches ;
next     8.2;

8.2
date     86.12.05.10.48.04;  author jws;  state Exp;
branches ;
next     8.1;

8.1
date     86.11.27.12.16.32;  author jws;  state Exp;
branches ;
next     7.1;

7.1
date     86.11.20.14.25.01;  author hal;  state Exp;
branches ;
next     6.1;

6.1
date     86.11.04.18.20.54;  author paws;  state Exp;
branches ;
next     5.1;

5.1
date     86.10.28.17.08.51;  author hal;  state Exp;
branches ;
next     4.3;

4.3
date     86.10.20.12.34.12;  author hal;  state Exp;
branches ;
next     4.2;

4.2
date     86.10.20.10.23.35;  author hal;  state Exp;
branches ;
next     4.1;

4.1
date     86.09.30.20.05.27;  author hal;  state Exp;
branches ;
next     3.8;

3.8
date     86.09.30.16.01.35;  author hal;  state Exp;
branches ;
next     3.7;

3.7
date     86.09.19.17.22.15;  author hal;  state Exp;
branches ;
next     3.6;

3.6
date     86.09.19.16.30.18;  author hal;  state Exp;
branches ;
next     3.5;

3.5
date     86.09.19.15.15.24;  author hal;  state Exp;
branches ;
next     3.4;

3.4
date     86.09.16.15.20.49;  author hal;  state Exp;
branches ;
next     3.3;

3.3
date     86.09.13.13.14.51;  author hal;  state Exp;
branches ;
next     3.2;

3.2
date     86.09.01.15.43.58;  author hal;  state Exp;
branches ;
next     3.1;

3.1
date     86.09.01.12.15.43;  author hal;  state Exp;
branches ;
next     2.5;

2.5
date     86.08.20.18.59.52;  author hal;  state Exp;
branches ;
next     2.4;

2.4
date     86.08.19.15.42.43;  author hal;  state Exp;
branches ;
next     2.3;

2.3
date     86.08.13.16.12.41;  author hal;  state Exp;
branches ;
next     2.2;

2.2
date     86.07.30.18.03.32;  author hal;  state Exp;
branches ;
next     2.1;

2.1
date     86.07.30.15.03.55;  author hal;  state Exp;
branches ;
next     1.5;

1.5
date     86.07.28.15.13.10;  author hal;  state Exp;
branches ;
next     1.4;

1.4
date     86.07.28.14.04.46;  author hal;  state Exp;
branches ;
next     1.3;

1.3
date     86.07.28.13.43.56;  author hal;  state Exp;
branches ;
next     1.2;

1.2
date     86.07.28.13.36.34;  author hal;  state Exp;
branches ;
next     1.1;

1.1
date     86.06.30.16.25.32;  author danm;  state tmp;
branches ;
next     ;


desc
@Base file for PWS 3.2 release.

@


56.4
log
@Changes to bring the McBeth drive on line at unit #41 or #42.
@
text
@					       (*

 (c) Copyright Hewlett-Packard Company 1983,
1984, 1985, 1987, 1989, 1990, 1991.
All rights are reserved.  Copying or other
reproduction of this program except for archival
purposes is prohibited without the prior
written consent of Hewlett-Packard Company.


	    RESTRICTED RIGHTS LEGEND

Use, duplication, or disclosure by the U.S. Government
is subject to restrictions as set forth in
subdivision (b)(3)(ii) of the Rights in Technical
Data and Computer Software clause at 52.227-7013.
Hewlett-Packard Company, 3000 Hanover Street,
Palo Alto CA 94304
						 *)


$page, sysprog$
$ALLOW_PACKED ON$ { JWS 4/10/85 }
$partial_eval on$

(********************************************************)
(*                                                      *)
(*  Note: You will need to use one of the following     *)
(*  compiler directives if the 'INTERFACE'              *)
(*  file is not in your current LIBRARY.                *)
(*  Choose the appropriate volume name  for             *)
(*  your configuration. If you are using                *)
(*  double-sided 3-1/2" media, the INTERFACE            *)
(*  file will be found on the ACCESS: volume.           *)
(*                                                      *)
(*  $search  'CONFIG:INTERFACE.'$                       *)
(*  $search  'ACCESS:INTERFACE.'$                       *)
(*                                                      *)
(********************************************************)

program {self-configuring} ctable;

module options;

  (********************************************)
  (* Choose the desired configuration options *)
  (* by editing the CONSTant declarations in  *)
  (* this module.                             *)
  (********************************************)

import
  sysglobals;

export

{INTERNAL ONLY BEGIN}
{ All internal-only code begins and ends as above and below.
{ MKCTBETA creates customer version from this internal source,
{ and it requires exactly the same spacing and capitalization
{ as in this example.  If there is an external version of
{ some code, it is introduced in an internal block like this
{EXTERNAL VERSION
{INTERNAL ONLY END}

{two possible versions of TABLE}
  const
    hfsversion  = 2;    { LIF primary DAM, HFS secondary }
    ucsdversion = 1;    { LIF primary DAM, UCSD secondary }

{change this assignment to get different versions}
  const
    thisversion = hfsversion;

{power-up system unit}
  const
    specified_system_unit =
      0;  {<>0 overrides auto-assignment}


{floppy/harddisc unit number slot tradeoff's}
  const
    floppy_unit_pairs =  {[1..10]}
      3;
    first_harddisc_lun = {do not edit!}
      7+(floppy_unit_pairs-1)*2;
    last_harddisc_lun =
      40;

$page$

{local printer type option}
  type
    local_printer_type = (HPIB, RS232, PARALLEL); {12/89 DEW - added PARALLEL}
  const
    local_printer_option = HPIB;


{local printer timeout}
  {
    maximum allowed delay between any two bytes:
      >0  specifies milliseconds (up to one hour)
      =0  specifies infinite timeout

    recommended values:
      -  HP2630 series  (HP-IB)       3000
      -  HP2670 series  (HP-IB)       3000
      -  HP9876         (HP-IB)       7000
      -  HP82905        (HP-IB)      12000
    Note: the HP82905 is currently NOT supported
      due to its improper response to interface
      clear (IFC), and its incompatible graphics
      dump sequence.

      -  HP LaserJet    (PARALLEL)   10000
  }
  const
    local_printer_timeout =
      $IF local_printer_option=HPIB$
	12000;  {milliseconds}
      $END$
      $IF local_printer_option=RS232$
	0;      {infinite}
      $END$
      $IF local_printer_option=PARALLEL$
	10000;  {milliseconds}
      $END$


{default dav's for devices not found by scanning}
  type
    dav_type = {device address vector}
      packed record
	sc, ba, du, dv: -128..127;
      end;
  const
    HP9885_default_dav =
      dav_type[sc: 12, ba: -1, du:  0, dv: -1];
    SRM_default_dav =
      dav_type[sc: 21, ba: {node} 0,
	       du: {unit} 8, dv: -1];
    BUBBLE_default_dav =
      dav_type[sc: 30, ba:  0, du:  0, dv:  0];
    local_HPIB_printer_default_dav =
      dav_type[sc:  7, ba:  1, du: -1, dv: -1];
    local_RS232_printer_default_dav =
      dav_type[sc:  9, ba:  0, du: -1, dv: -1];
    local_PARALLEL_printer_default_dav =
      dav_type[sc:  23, ba:  0, du: -1, dv: -1];

$page$

{local hard disc partitioning parameters}
  type
    pp_type =  {partitioning parameters}
      record
	mvs: integer;   {min vol size in bytes}
	mnv: shortint;  {max number of volumes}
      end;
  {   In general, MNV puts an upper bound on the
    number of logical volumes that a physical
    volume can be partitioned into.  Depending
    upon MNV's range, however, several types of
    behavior can occur.
      If MNV=0, then no logical volumes will ever
    be assigned for the device.
      If abs(MNV)=1, then exactly one logical
    volume will be assigned per physical volume
    of the device.  This corresponds to the
    2.X CTABLE's "single_volume" mode.
      If MNV>1, then partitioning will always be
    performed, subject to meeting the minimum
    volume size restrictions.  This corresponds
    to the 2.X CTABLE's "multi_volume" mode.
      If MNV<-1, then partitioning will be
    performed, but afterwards any logical volume
    that does not contain a valid directory will
    be coalesced with a previous adjacent logical
    volume if that one DOES contain a valid
    directory. As an extreme case, if only a
    single directory exists, and it is at the
    beginning of the physical volume, then all
    following logical volumes will be coalesced
    with the first, providing the same behavior
    as the 2.X CTABLE's "auto_volume" mode. With
    the less extreme cases, a wide variety of
    partitioning options are now possible without
    modification to CTABLE.                     }
  const
    min_size = {in bytes [1..maxint]}
      1000000;
    max_vols = {[-30..30]; <0 means autocoalesce}
      -30;
    HP913X_A_pp =
      pp_type[mvs: min_size, mnv: max_vols];
    HP913X_B_pp =
      pp_type[mvs: min_size, mnv: max_vols];
    HP913X_C_pp =
      pp_type[mvs: min_size, mnv: max_vols];
{INTERNAL ONLY BEGIN}
    HP7905_pp =  {historical value of mvs}
      pp_type[mvs:   983040, mnv: max_vols];
    HP7906_pp =  {historical value of mvs}
      pp_type[mvs:   983040, mnv: max_vols];
    HP7920_pp =
      pp_type[mvs: min_size, mnv: max_vols];
    HP7925_pp =
      pp_type[mvs: min_size, mnv: max_vols];
{INTERNAL ONLY END}
    CS80disc_pp =
      pp_type[mvs: min_size, mnv: max_vols];
    SCSIdisc_pp =                                {DEW 9/89 - added SCSI support}
      pp_type[mvs: min_size, mnv: max_vols];
$page$

{system unit auto-search declarations}
  const
    sysunit_list_length =
      7;
  type
    sysunit_list_type =
      array[1..sysunit_list_length] of unitnum;
  const
    sysunit_list =
      sysunit_list_type[
	  first_harddisc_lun, {first hard disc logical unit number}
	  45,   {srm, prefixed to user's sysvol}
	  4,    {floppy unit 1, primary DAM}
	  44,   {floppy unit 1, secondary DAM}
	  3,    {floppy unit 0, primary DAM}
	  43,   {floppy unit 0, secondary DAM}
	  42];  {bubble}


{HP-IB select code scanning declarations}
  const
    sc_list_length =
      3;
  type
    sc_list_type =
      array[1..sc_list_length] of shortint;
  const
    sc_list =
      sc_list_type[
	  7,    {internal HP-IB}
	  8,    {default sc for HP98624 HP-IB}
	  14];  {default sc for HP98625 HP-IB}

{SCSI select code scanning declarations}
  const
    SCSIsc_list_length =
      3;
  type
    SCSIsc_list_type =
      array[1..SCSIsc_list_length] of shortint;
  const
    SCSIsc_list =
      SCSIsc_list_type[
	  14,    {default sc for HP98265A (internal) and HP98658A (external)}
	  15,    {external SCSI sc when internal HP-IB/SCSI present at sc 14}
	  28];   {internal SCSI on 340/345}

{
  SCSI removable media may be an optical disk which has capacities of
  greater than 300Meg!  Therefore removable media can be configured to
  be:
	1:  A Hard disk if it has a size greater than 10M.
	2:  A Hard disk always.
	3:  A Floppy disk always.


  Things to be aware of when SCSI removable media is being treated like a
  hard disk:

    1: If the removable media is not on line at the time CTABLE is executed,
       the size of the disk is not available.  If the AllAreHard option is
       being used, then a unit entry will NOT be created for it.  If the
       AllOver10MAreHard option is used, then a unit entry for a floppy disk
       will be created for it.

    2: CTABLE will attempt the PREVENT MEDIUM REMOVAL command.  Through the
       SCSI programmer's interface, the ALLOW MEDIUM REMOVAL command may be
       sent.

    3: If the removable media goes off line for any reason, such as removing
       the media, PWS will discontinue communication with that device until
       CTABLE has been rerun.
}
   type
	SCSIRemovableOptionsType = (AllOver10MAreHard,
				    AllAreHard,
				    AllAreFloppy);
   const
	SCSIRemovableOption = AllOver10MAreHard;



implement {options}

end; {options}
$page, range off, ovflcheck off, partial_eval on$

module ctr; {ctable routines}

  (********************************************)
  (*                                          *)
  (*               Warning:                   *)
  (*   This module should not be modified!    *)
  (*                                          *)
  (********************************************)

import
  sysglobals, loader, options, ldr, fs, bootdammodule;

export

  const {mass storage letter specifiers}
    INTERNAL  = 'M';
    HP8290X   = 'N';
    HP9885    = 'F';
    HP9895    = 'H';
    HP913X_A  = 'U';
    HP913X_B  = 'V';
    HP913X_C  = 'W';
{INTERNAL ONLY BEGIN}
    HP7905    = 'Y';
    HP7906    = 'C';
    HP7920    = 'P';
    HP7925    = 'X';
{INTERNAL ONLY END}
    CS80      = 'Q';
    SRM       = 'G';
    PRINTER   = 'J';
    RAM       = 'R';
    BUBBLE    = 'B';
    EPROM     = 'E';
    SCSI      = 'S';      {DEW 09/89 - added SCSI support}
    NODEVICE  = #255;


  type
    flpy_flags_type = {flags governing floppy unit pair assignments}
      packed record
	assign_even_unit, assign_odd_unit: boolean;
      end;

  const
    assign_neither_flpy_unit =
      flpy_flags_type[assign_even_unit: false, assign_odd_unit: false];
    assign_both_flpy_units =
      flpy_flags_type[assign_even_unit: true, assign_odd_unit: true];

  type
    MSUS_type = {Mass Storage Unit Specifier}
      record
	flpy_flags: flpy_flags_type;
	letter: char;  {from the above mass storage letter specifiers}
	dav: dav_type;
      end;
$page$

    mp_type =  {medium parameters}
      record
	tpm: integer;  {tracks per medium}
	bpt: integer;  {bytes per track}
      end;

    ds_type =  {Directory access method Specifier for local mass storage}
      ( primary_dam,     {normally LIF }
	secondary_dam,   {HFS or UCSD, depending on choice in options}
	LIF_dam,         {LIF, regardless of primary/secondary choice}
	UCSD_dam,        {UCSD, regardless of primary/secondary choice}
	HFS_dam   );     {HFS, regardless of primary/secondary choice}

  var
    bootdev_MSUS: MSUS_type;
    bootdev_lun: unitnum;
    hfs_installed: boolean;

  procedure create_temp_unitable;
  procedure assign_and_clear_unit(lunit: unitnum);
  procedure assign_temp_unitable;
  function sysunit_ok(system_unit: unitnum): boolean;
  procedure zap_assigned_unit(lunit: unitnum);
  function on_same_medium(lun1, lun2: unitnum): boolean;
  procedure remove_extraneous_volumes(first_lun, last_lun: unitnum);
  function medium_parameters(letter: char): mp_type;
  function partitioning_parameters(letter: char): pp_type;
  function number_vols(mp: mp_type; pp: pp_type): shortint;
  function svol_bytes(letter: char): integer;
  function vol_bytes(current_vol, number_vols: shortint; mp: mp_type): integer;
  function vol_offset(current_vol, number_vols: shortint; mp: mp_type): integer;
  function block_boundaries(mp: mp_type): mp_type;
  function value(symbol: string255): integer;
  function MSUSs_match(MSUS1, MSUS2: MSUS_type): boolean;
  procedure extra_HFS_unit(oldun, newun: unitnum; prefix: string255);
  procedure install_HFS(un: unitnum; force: boolean);



  { table entry assignment procedures }

  procedure tea_memory_volume_dam(ds:ds_type);
  procedure tea_boot(un:unitnum);
  procedure tea_srm(un:unitnum;sc,ba,du:shortint);
  procedure tea_crt(un:unitnum);
  procedure tea_kbd(un:unitnum);
  procedure tea_local_printer(un:unitnum;sc,ba:shortint;uvid:vid;bto:integer);
  procedure tea_mini(un:unitnum;ds:ds_type;du:shortint);
  procedure tea_HP9885(un:unitnum;ds:ds_type;sc,du,block_os:shortint);
  procedure tea_HP9895(un:unitnum;ds:ds_type;sc,ba,du,block_os:shortint);
  procedure tea_HP8290X(un:unitnum;ds:ds_type;sc,ba,du:shortint);
  procedure tea_flpy(un:unitnum;lr:char;ds:ds_type;sc,ba,du:shortint);
{INTERNAL ONLY BEGIN}
  procedure tea_amigo_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;os:integer;lr:char;mb:integer);
{INTERNAL ONLY END}
  procedure tea_amigo_sv(un:unitnum;ds:ds_type;sc,ba,du:shortint;os:integer;lr:char;mb:integer);
  procedure tea_CS80_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;
					    os,id,mb,disksize:integer);
  procedure tea_CS80_sv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint);
  procedure tea_BUBBLE(un:unitnum;ds:ds_type;sc:shortint);
  procedure tea_EPROM(un:unitnum;ds:ds_type;sn:shortint);
  procedure tea_SCSI_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;
					    os,id,mb,disksize:integer); {DEW 09/89 - added SCSI support}
  procedure tea_SCSI_sv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint);    {DEW 09/89 - added SCSI support}
  { JWH 6/93 : }
  procedure tea_SCSI_tape(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint);
$page$

implement {ctr}

const  {abbreviation for tea procedure calls}
  T = true;
  F = false;

const  {actual driver entry point names}
  NO_DAM_name         = 'INITUNITS_NODAM';
  BOOT_DAM_name       = 'BOOTDAMMODULE_BOOTDAM';
  LIF_DAM_name        = 'LIFMODULE_LIFDAM';
  UCSD_DAM_name       = 'UCSDMODULE_UCSD_DAM';
  UNBLOCKED_DAM_name  = 'MISC_UNBLOCKEDDAM';
  SRM_DAM_name        = 'SRMDAMMODULE_SRMDAM';
  HFS_DAM_name        = 'HFS_DAM_MODULE_HFSDAM';

  NULL_TM_name        = 'INITUNITS_NOUNIT';
  BOOT_TM_name        = 'BOOTDAMMODULE_BOOTTM';
  CRT_TM_name         = 'SYSDEVS_CRTIO';
  KBD_TM_name         = 'SYSDEVS_KBDIO';
  MINI_TM_name        = 'MINI_MINIIO';
  SRM_TM_name         = 'SRMAMMODULE_SRMAM';
  PRINTER_TM_name     = 'PRTDVR_PRTIO';
  F9885_TM_name       = 'F9885DVR_F9885IO';
  AMIGO_TM_name       = 'AMIGODVR_AMIGOIO';
  CS80_TM_name        = 'CS80DVR_CS80IO';
  BUBBLE_TM_name      = 'BUBBLE_BUB_TM';
  EPROM_TM_name       = 'EPROMS_EPROM_TM';
  HFS_TM_name         = 'HFS_TM_MODULE_HFSTM';
  SCSIDSC_TM_name     = 'SCSIDISCMODULE_SCSIDISC';{09/89 DEW - added SCSI support}


var
  temp_unitable: unitableptr;
  temp_h_unitable: ^h_unitabletype;

procedure delay_timer(t:integer); external; {JWS 6/16/87}

procedure swap_h_units(u: unitnum);
  var
    t_unit: h_unittype;
  begin
    t_unit := h_unitable^.tbl[u];
    h_unitable^.tbl[u] := temp_h_unitable^.tbl[u];
    temp_h_unitable^.tbl[u] := t_unit;
  end;

procedure check(parameter, lower_bound, upper_bound: integer);
  begin
    if (parameter<lower_bound) or (parameter>upper_bound) then
      halt(-8) {value range error}
  end;

$page$

function value(symbol: string255): integer;
  var
    modp: moddescptr;
    ptr, valueptr: addrec;
    found: boolean;
  begin {value}
    value := 0;
    found := false;
    modp := sysdefs;
    while (modp<>nil) and not found do
      with modp^ do
	begin
	  ptr := defaddr;
	  while (ptr.a<defaddr.a+defsize) and not found do
	    begin
	      found := ptr.syp^=symbol;
	      ptr.a := ptr.a+strlen(ptr.syp^)+1;
	      ptr.a := ptr.a+ord(odd(ptr.a));
	      valueptr.a := ptr.a+2;
	      if found then
		value := valueptr.vep^.value;
	      ptr.a := ptr.a+ptr.gvp^.short;
	    end; {while}
	  modp := link;
	end; {with modp^}
  end; {value}


function MSUSs_match(MSUS1, MSUS2: MSUS_type): boolean;
  begin {MSUSs_match}
    MSUSs_match := (MSUS1.letter = MSUS2.letter) and
		   (MSUS1.dav.sc = MSUS2.dav.sc) and
		   (MSUS1.dav.ba = MSUS2.dav.ba) and
		   (MSUS1.dav.du = MSUS2.dav.du) and
		   (MSUS1.dav.dv = MSUS2.dav.dv);
  end; {MSUSs_match}

{
{ Make a new unit table entry at newun (must be free).
{ The medium is the same as oldun (must be HFS).
{ Prefix the new unit to the given directory name.
}
procedure extra_HFS_unit(oldun, newun: unitnum; prefix: string255);
  label
    999;
  var
    old_h_unit: h_unittype;
    old_unit: unitentry;
    i, un: integer;
    kvid: vid;
    dirname: fid;
  begin
    { new unit must be unused }
    if unitable^[newun].letter <> #0 then
      goto 999;

    { old unit must be HFS }
    if h_unitable = NIL then    {protect against ^nil. SFB}
     goto 999;

    if not h_unitable^.tbl[oldun].is_hfsunit then
      goto 999;

    { save unitable, h_unitable entries at new unit }
    old_unit := unitable^[newun];
    old_h_unit := h_unitable^.tbl[newun];

    { make newun and oldun look the same }
    unitable^[newun] := unitable^[oldun];
    h_unitable^.tbl[newun] := h_unitable^.tbl[oldun];

    { do the prefix }
    setstrlen(dirname, 0);
    strwrite(dirname, 1, i, '#', newun:1, ':', prefix);
    doprefix(dirname, kvid, un, true);

    { if it failed, reset the new unit }
    if ioresult <> ord(inoerror) then begin
      unitable^[newun] := old_unit;
      h_unitable^.tbl[newun] := old_h_unit;
    end;

  999:
  end;

{
{ Install HFS on this unit.
{ force -> install HFS always
{ not force -> install HFS if superblock is there
}
procedure install_HFS(un: unitnum; force: boolean);
  var
    dam_proc:
      packed record case integer of
	0: (dam: damtype);
	1: (value, slink: integer);
      end;

    tm_proc:
      packed record case integer of
	0: (tm: amtype);
	1: (value, slink: integer);
      end;
  begin
    if h_unitable <> nil then with h_unitable^ do begin
      call(init_unit_proc, un, force);
      { not force -> init_unit_proc sets is_hfsunit if recognized }
      if force or tbl[un].is_hfsunit then begin
	dam_proc.value := value(HFS_DAM_name);
	dam_proc.slink := 0;
	tm_proc.value := value(HFS_TM_name);
	tm_proc.slink := 0;
	with unitable^[un] do begin
	  dam := dam_proc.dam;
	  tm := tm_proc.tm;
	  uvid := '';
	end;
      end;
    end;
  end;


$page$

procedure tea {lowest-level Table Entry Assignment procedure}
    ( un:unitnum;                  {unit number}
      dam_name: string255;         {directory access method}
      tm_name: string255;          {transfer method (driver)}
      p_sc: shortint;              {select code}
      p_ba: shortint;              {bus address}
      p_du: shortint;              {disc unit}
      p_dv: shortint;              {disc volume}
      p_byteoffset: integer;       {physical starting byte of volume}
      p_devid: integer;            {device identifier (driver dependent)}
      p_uvid: vid;                 {volume id}
    { p_drvtemp: integer           {driver temp}
    { p_drvtemp2: shortint;        {second driver temp}
      p_letter: char;              {device specifier letter}
    { p_offline: boolean           {unit offline flag}
      p_uisinteractive: boolean;   {device echos input}
    { p_umediavalid: boolean;      {open files are valid}
    { p_uuppercase: boolean;       {volume name should be uppercased}
      p_uisfixed: boolean;         {medium not removable flag}
    { p_ureportchange: boolean;    {driver directive to report/ignore medium changes}
    { p_pad: 0..1                  {(not used)}
      p_uisblkd: boolean;          {blocked volume flag}
      p_umaxbytes: integer;        {volume size in bytes (unit)}
      p_disksize: integer  );      {volume size in bytes (disk)}

  var
    dam_proc:
      packed record case integer of
	0: (dam: damtype);
	1: (value, slink: integer);
      end;

    tm_proc:
      packed record case integer of
	0: (tm: amtype);
	1: (value, slink: integer);
      end;

    dam_ok: boolean;

    old_unit : unitentry;       {for "missing LIFDAM" bug fix. SFB}
		{This bug showed up when LIFDAM was not in INITLIB, but
		 HFSDAM was. If a superblock is on the disc, HFSDAM should
		 connect, but didn't, mainly because of the
		 'if (dam_proc.value <> 0)' test farther on.
		 We no longer do that test, but have to ensure the unit
		 doesn't get set up if the DAM is not available. SFB}

  procedure swap_temp_and_real_unit;
  var
     tmpunit: unitentry;
  begin
     tmpunit := unitable^[un];
     unitable^[un] := temp_unitable^[un];
     temp_unitable^[un] := tmpunit;
  end;

  begin {tea}
    if temp_unitable=nil then halt(-3); {unassigned pointer}

    { HFS only at beginning of disk (RAM units never tea'd) }
    if (dam_name = HFS_DAM_name) and (p_byteoffset <> 0) then
      dam_name := '';  {was LIF_DAM_name. Need value=0. SFB}

    dam_proc.value := value(dam_name);
    dam_proc.slink := 0;

    tm_proc.value := value(tm_name);
    tm_proc.slink := 0;

    old_unit := temp_unitable^[un]; {to restore later, if DAM not found. SFB}

    if
   { (dam_proc.value<>0) and           {removed. SFB}
     (tm_proc.value<>0) then  {assign the entry}
      begin

	with temp_unitable^[un] do
	  begin
	    dam             := dam_proc.dam;
	    tm              := tm_proc.tm;
	    sc              := p_sc;
	    ba              := p_ba;
	    du              := p_du;
	    dv              := p_dv;
	    byteoffset      := p_byteoffset;
	    devid           := p_devid;
	    uvid            := p_uvid;
	    dvrtemp         := 0;                 {always initially zero!}
	    dvrtemp2        := -1;                {always initially -1!}
	    letter          := p_letter;
	    offline         := false;             {always initially online!}
	    uisinteractive  := p_uisinteractive;
	    umediavalid     := false;             {never valid to start with}
	    uuppercase      := not p_uisblkd;     {assume case is significant}
	    uisfixed        := p_uisfixed;
	    ureportchange   := true;              {do report media changes}
	    pad             := 0;                 {not used}
	    uisblkd         := p_uisblkd;
	    if uisblkd then
	      umaxbytes     := p_umaxbytes;

	    if ( (tm_name = SCSIDSC_TM_name) and
		 ( (SCSIRemovableOption = AllAreHard) or
		   ( (SCSIRemovableOption = AllOver10MAreHard) and
		     (p_disksize >= hex('A00000'))
		   )
		 )
	       ) then
			pad := 1;
	  end; {with}


	if hfsbflg then
	  dam_ok := value(HFS_DAM_name)<>0      {SFB}
	else
	  if dam_proc.value <> 0 then           {SFB}
	    dam_ok := (dam_name=LIF_DAM_name) or (dam_name=SRM_DAM_name);

	with bootdev_MSUS, dav do {see if this entry points to it}
	  if (p_letter=letter) and  {wish we could use MSUSs_match function}
	     (p_sc=sc) and (p_ba=ba) and (p_du=du) and (p_dv=dv) and
	     dam_ok and
	     (p_byteoffset=0) then  {remember this unit number!}
	    bootdev_lun := un;

	if h_unitable <> nil then with h_unitable^ do begin
	  { temporarily swap temp and real unit entries }
	  swap_h_units(un);
	  swap_temp_and_real_unit;

	  if dam_name = HFS_DAM_name then
	    { force this unit to be HFS }
	    install_HFS(un, true)
	  else
	  if (p_byteoffset = 0)
	{ and (dam_name = LIF_DAM_name) {removed, as it blocks WS1.0, etc. SFB}
	  and (un >= first_harddisc_lun)
	  and (un <= last_harddisc_lun) then
	    { install HFS if disk has a superblock }
	    install_HFS(un, false);

	  if tbl[un].is_hfsunit then begin
	    { take up whole disk }
	    if p_disksize <> 0 then
	      unitable^[un].umaxbytes := p_disksize;
	    { prevent further units on this disk }
	    hfs_installed := true;
	  end;
	  swap_h_units(un);
	  swap_temp_and_real_unit;
	end;

      end; {if}

    {see if we found a dam for the unit. SFB}
    if temp_h_unitable <> NIL then
     with temp_h_unitable^ do   {was DAM found or HFS installed ?}
      begin
       if (not tbl[un].is_hfsunit) and (dam_proc.value=0) then
	temp_unitable^[un]:=old_unit  {if not, uninstall the entry. SFB}
      end
    else        {no possibility HFSDAM was installed}
     if dam_proc.value=0 then
      temp_unitable^[un]:=old_unit;   {if no dam, uninstall the entry. SFB}

  end; {tea}


function dam(ds: ds_type): string255;
  begin
    case ds of
$if thisversion = hfsversion$
      primary_dam:
	dam := LIF_DAM_name;
      secondary_dam:
	dam := HFS_DAM_name;
$end$
$if thisversion = ucsdversion$
      primary_dam:
	dam := LIF_DAM_name;
      secondary_dam:
	dam := UCSD_DAM_name;
$end$
      HFS_dam:
	dam := HFS_DAM_name;
      LIF_dam:
	dam := LIF_DAM_name;
      UCSD_dam:
	dam := UCSD_DAM_name;
    end; {case}
  end;
$page$

function medium_parameters(letter: char): mp_type;
  const {LOGICAL sizes unless otherwise noted}
    INTERNAL_mp = mp_type[tpm: 2* 33, bpt: 16*256];
    HP8290X_mp  = mp_type[tpm: 2* 33, bpt: 16*256];
    HP9885_mp   = mp_type[tpm: 1* 77, bpt: 30*256];  {physical size}
    HP9895_mp   = mp_type[tpm: 2* 77, bpt: 30*256];  {physical size}
    HP913X_A_mp = mp_type[tpm: 4*152, bpt: 31*256];
    HP913X_B_mp = mp_type[tpm: 4*305, bpt: 31*256];
    HP913X_C_mp = mp_type[tpm: 6*305, bpt: 31*256];
{INTERNAL ONLY BEGIN}
    HP7905_mp   = mp_type[tpm: 2*400, bpt: 48*256];  {fixed is half this size}
    HP7906_mp   = mp_type[tpm: 2*400, bpt: 48*256];  {fixed & remov same size}
    HP7920_mp   = mp_type[tpm: 5*800, bpt: 48*256];
    HP7925_mp   = mp_type[tpm: 9*800, bpt: 64*256];
{INTERNAL ONLY END}
    BUBBLE_mp   = mp_type[tpm: 1*512, bpt:  1*256];  {1 megabit unit}
   {BUBBLE_mp   = mp_type[tpm: 4*512, bpt:  1*256];} {4 megabit unit}
    null_mp     = mp_type[tpm:     0, bpt:      0];
  begin
    case letter of
      INTERNAL:  medium_parameters := INTERNAL_mp;
      HP8290X:   medium_parameters := HP8290X_mp;
      HP9885:    medium_parameters := HP9885_mp;
      HP9895:    medium_parameters := HP9895_mp;
      HP913X_A:  medium_parameters := HP913X_A_mp;
      HP913X_B:  medium_parameters := HP913X_B_mp;
      HP913X_C:  medium_parameters := HP913X_C_mp;
{INTERNAL ONLY BEGIN}
      HP7905:    medium_parameters := HP7905_mp;
      HP7906:    medium_parameters := HP7906_mp;
      HP7920:    medium_parameters := HP7920_mp;
      HP7925:    medium_parameters := HP7925_mp;
{INTERNAL ONLY END}
      BUBBLE:    medium_parameters := BUBBLE_mp;
      otherwise  medium_parameters := null_mp;
    end; {case}
  end;


function partitioning_parameters(letter: char): pp_type;
  const
    null_pp = pp_type[mvs: 0, mnv: 0];
  begin
    case letter of
      HP913X_A:  partitioning_parameters := HP913X_A_pp;
      HP913X_B:  partitioning_parameters := HP913X_B_pp;
      HP913X_C:  partitioning_parameters := HP913X_C_pp;
{INTERNAL ONLY BEGIN}
      HP7905:    partitioning_parameters := HP7905_pp;
      HP7906:    partitioning_parameters := HP7906_pp;
      HP7920:    partitioning_parameters := HP7920_pp;
      HP7925:    partitioning_parameters := HP7925_pp;
{INTERNAL ONLY END}
      CS80:      partitioning_parameters := CS80disc_pp;
      SCSI:      partitioning_parameters := SCSIdisc_pp;        {DEW 09/89 - added SCSI support}
      otherwise  partitioning_parameters := null_pp;
    end; {case}
  end;
$page$

function number_vols(mp: mp_type; pp: pp_type): shortint;
  var
    nvols: shortint;
  begin
    if pp.mnv<0 then  {negative implies autovolume feature; use absolute value}
      pp.mnv := -pp.mnv;
    if pp.mvs<=0 then pp.mvs := 1;  {guard against div's by 0}
    if mp.bpt<=0 then mp.bpt := 1;  {guard against div's by 0}
    nvols := mp.tpm div ((pp.mvs+mp.bpt-1) div mp.bpt);
    if (nvols=0) and (mp.tpm>0) then
      nvols := 1;  {physical vol smaller than the specified minimum vol size}
    if nvols>pp.mnv then  {cut back, even to zero if specified}
      nvols := pp.mnv;
    number_vols := nvols;
  end;


function svol_bytes(letter: char): integer;
  var
    mp: mp_type;
  begin
    mp := medium_parameters(letter);
    svol_bytes := mp.bpt*mp.tpm;  {single volume bytes}
  end;


function vol_bytes(current_vol, number_vols: shortint; mp: mp_type): integer;
  var
    tracks: integer;
  begin
    tracks := mp.tpm div number_vols;           {each vol gets this much}
    if current_vol=number_vols-1 then
      tracks := tracks+mp.tpm mod number_vols;  {last vol gets any extra}
    vol_bytes := tracks*mp.bpt;
  end;


function vol_offset(current_vol, number_vols: shortint; mp: mp_type): integer;
  begin
    vol_offset := (mp.tpm div number_vols)*current_vol*mp.bpt;
  end;


function block_boundaries(mp: mp_type): mp_type;
  begin
    block_boundaries.tpm := mp.tpm*mp.bpt div 512;
    block_boundaries.bpt := 512;
  end;
$page$

{ standard driver-oriented table entry assignment procedures }


procedure tea_nounit(un:unitnum);
  begin
    tea(un,NO_DAM_name,NULL_TM_name,0,0,0,0,0,0,'',#0,F,F,F,0,0);
  end;


procedure tea_memory_volume_dam(ds:ds_type);
  begin
    tea(0,dam(ds),NULL_TM_name,0,0,0,0,0,0,'',RAM,F,T,T,0,0);
  end;


procedure tea_crt(un:unitnum);
  begin
    tea(un,UNBLOCKED_DAM_name,CRT_TM_name,0,0,0,0,0,0,'CONSOLE',#0,T,T,F,0,0);
  end;


procedure tea_kbd(un:unitnum);
  begin
    tea(un,UNBLOCKED_DAM_name,KBD_TM_name,0,0,0,0,0,0,'SYSTERM',#0,F,T,F,0,0);
  end;


procedure tea_mini(un:unitnum;ds:ds_type;du:shortint);
  begin
    check(du, 0, 1);
    tea(un,dam(ds),MINI_TM_name,0,0,du,0,0,0,'',INTERNAL,
			      F,F,T,svol_bytes(INTERNAL),0);
  end;


procedure tea_boot(un: unitnum);
  begin
    tea(un,BOOT_DAM_name,BOOT_TM_name,0,0,0,0,0,0,'',#0,F,F,T,maxint,0);
  end;


procedure tea_srm(un:unitnum;sc,{node}ba,{unit}du:shortint);
  begin
    check(sc, 7, 31);
    check(ba, 0, 127);
    if du<>0 then check(du, 7, 26);
    tea(un,SRM_DAM_name,SRM_TM_name,sc,ba,du,0,0,0,'',SRM,F,T,T,maxint,0);
  end;


procedure tea_local_printer(un:unitnum;sc,ba:shortint;uvid:vid;bto:integer);
  begin
    check(sc, 7, 31);
    check(ba, 0, 30);
    check(bto, 0, 60*60*1000);  {one hour should be enough!}
    tea(un,UNBLOCKED_DAM_name,PRINTER_TM_name,sc,ba,0,0,0,bto,uvid,#0,
							    F,T,F,0,0);
  end;
$page$

procedure tea_HP9885(un:unitnum;ds:ds_type;sc,du,block_os:shortint);
  var
    os: integer;
  begin
    check(sc, 8, 31);
    check(du, 0, 3);
    os := block_os*512;
    check(os, 0, svol_bytes(HP9885)-1);
    tea(un,dam(ds),F9885_TM_name,sc,0,du,0,os,0,'',HP9885,
			    F,F,T,svol_bytes(HP9885)-os,0);
  end;


procedure tea_HP9895(un:unitnum;ds:ds_type;sc,ba,du,block_os:shortint);
  var
    os: integer;
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 3);
    os := block_os*512;
    check(os, 0, svol_bytes(HP9895)-1);
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,0,os,0,'',HP9895,
			       F,F,T,svol_bytes(HP9895)-os,0);
  end;


procedure tea_HP8290X(un:unitnum;ds:ds_type;sc,ba,du:shortint);
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 3);
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,0,0,0,'',HP8290X,
				  F,F,T,svol_bytes(HP8290X),0);
  end;


procedure tea_amigo_sv(un:unitnum;ds:ds_type;sc,ba,du:shortint;os:integer;lr:char;mb:integer);
  var
    medium_size: integer;
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 7);
{INTERNAL ONLY BEGIN}
    if not (lr in [HP913X_A, HP913X_B, HP913X_C, HP7920, HP7925]) then
{EXTERNAL VERSION
    if not (lr in [HP913X_A, HP913X_B, HP913X_C]) then
{INTERNAL ONLY END}
      halt(-8); {value range error}
    medium_size := svol_bytes(lr);
    check(os, 0, medium_size-1);
    if os mod 256<>0 then halt(-8) {value range error};
    check(mb, 1, medium_size-os);
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,0,os,0,'',lr,F,T,T,mb,medium_size);
  end;
$page$

{INTERNAL ONLY BEGIN}
procedure tea_amigo_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;os:integer;lr:char;mb:integer);
  var
    medium_size: integer;
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 7);
    check(dv, 0, 1);
    if not (lr in [HP7905, HP7906]) then halt(-8);  {value range error}
    medium_size := svol_bytes(lr);
    if (lr=HP7905) and (dv<>0) then
      medium_size := medium_size div 2;  {7905 fixed is half as big!}
    check(os, 0, medium_size-1);
    if os mod 256<>0 then halt(-8) {value range error};
    check(mb, 1, medium_size-os);
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,dv,os,0,'',lr,F,T,T,mb,medium_size);
  end;
{INTERNAL ONLY END}
$page$

procedure tea_CS80_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;os,id,
						   mb,disksize:integer);
  {
    CS80 multiple (logical) volume assignment procedure:
    1) devid must match the actual HP product number as found in describe
    2) offset and umaxbytes are fixed
    3) the uisfixed field is assigned by the driver in the clearunit procedure
  }
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 14);
    check(dv, 0, 7);
    tea(un,dam(ds),CS80_TM_name,sc,ba,du,dv,os,id,'',CS80,F,F,T,mb,disksize);
  end;


procedure tea_CS80_sv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint);
  {
    CS80 single (logical) volume assignment procedure:
    1) byteoffset always assumed to be zero
    2) umaxbytes is dependent upon the media loaded, thus it is set by the
       driver at clearunit time and whenever it detects a media change.
       BOTTOM LINE: the medium CANNOT be partitioned into multiple volumes!
    3) the uisfixed field is assigned by the driver in the clearunit procedure
    4) device can either be a disc (presumably a floppy) or a tape
  }
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 14);
    check(dv, 0, 7);
    tea(un,dam(ds),CS80_TM_name,sc,ba,du,dv,0,-1,'',CS80,F,F,T,0,0);
  end;


procedure tea_SCSI_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;os,id,
						   mb,disksize:integer);
  {
    09/89 DEW - added SCSI support
    SCSI multiple (logical) volume assignment procedure:
    1) devid must match the actual HP product number as found in describe
    2) offset and umaxbytes are fixed
    3) the uisfixed field is assigned by the driver in the clearunit procedure
  }
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 255);
    check(dv, 0, 0);   {SCSI Secondary Units not supported}
    tea(un,dam(ds),SCSIDSC_TM_name,sc,ba,du,dv,os,id,'',SCSI,F,F,T,mb,disksize);
  end;


procedure tea_SCSI_sv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint);
  {
    09/89 DEW - added SCSI support
    SCSI single (logical) volume assignment procedure:
    1) byteoffset always assumed to be zero
    2) umaxbytes is dependent upon the media loaded, thus it is set by the
       driver at clearunit time and whenever it detects a media change.
       BOTTOM LINE: the medium CANNOT be partitioned into multiple volumes!
    3) the uisfixed field is assigned by the driver in the clearunit procedure
    4) device can either be a disc (presumably a floppy) or a tape
  }
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 255);
    check(dv, 0, 0);   {SCSI Secondary Units not supported}
    tea(un,dam(ds),SCSIDSC_TM_name,sc,ba,du,dv,0,-1,'',SCSI,F,F,T,0,0);
  end;

 { JWH 6/93. Same as tea_SCSI_sv except we DO set
    dvrtemp (blocksize) here.
  }
procedure tea_SCSI_tape(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint);
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 255);
    check(dv, 0, 0);   {SCSI Secondary Units not supported}
    { tape -2 for devid }
    if temp_unitable^[un].letter = chr(0) then
     begin
      tea(un,dam(ds),SCSIDSC_TM_name,sc,ba,du,dv,0,-2,'',SCSI,F,F,T,0,0);
      temp_unitable^[un].dvrtemp := 65536; { blocksize }
      temp_unitable^[un].umaxbytes := 0; { set by BACKUP.CODE }
     end
    else { put at unit + 1 (unit 42) }
     begin
      tea(un+1,dam(ds),SCSIDSC_TM_name,sc,ba,du,dv,0,-2,'',SCSI,F,F,T,0,0);
      temp_unitable^[un+1].dvrtemp := 65536; { blocksize }
      temp_unitable^[un+1].umaxbytes := 0; { set by BACKUP.CODE }
     end;
  end;

procedure tea_flpy(un:unitnum;lr:char;ds:ds_type;sc,ba,du:shortint);
  begin
    case lr of
      INTERNAL: tea_mini(un,ds,du);
      HP8290X:  tea_HP8290X(un,ds,sc,ba,du);
      CS80:     tea_CS80_sv(un,ds,sc,ba,du,0);
      SCSI:     tea_SCSI_sv(un,ds,sc,ba,du,0);  {DEW 09/89 - added SCSI support}
      HP9885:   tea_HP9885(un,ds,sc,du,0);
      HP9895:   tea_HP9895(un,ds,sc,ba,du,0);
      otherwise halt(-8) {value range error}
    end;  {case}
  end;

$page$

procedure tea_BUBBLE(un:unitnum;ds:ds_type;sc:shortint);
  begin
    { NOTE THAT UMAXBYTES IS ASSIGNED AT CLEARUNIT TIME }
    check(sc,7,31);
    tea(un,dam(ds),BUBBLE_TM_name,sc,0,0,0,0,0,'',BUBBLE,F,T,T,0,0);
  end;

procedure tea_EPROM(un:unitnum;ds:ds_type;sn:shortint);
  begin
    { NOTE THAT UMAXBYTES IS ASSIGNED AT CLEARUNIT TIME }
    check(sn,0,MAXUNIT);
    tea(un,dam(ds),EPROM_TM_name,0,0,0,sn,0,0,'',EPROM,F,T,T,0,0);
  end;

$page$

procedure create_temp_unitable;
  var
    lunit: unitnum;
  begin
    new(temp_unitable);
    tea_nounit(0);  {assign one dummy entry}
    for lunit := 1 to maxunit do  {copy others; avoid symbol table search each time!}
      temp_unitable^[lunit] := temp_unitable^[0];
    if h_unitable <> nil then begin
      new(temp_h_unitable);
      temp_h_unitable^ := h_unitable^;
      call(h_unitable^.init_cache_proc);
      for lunit := 0 to maxunit do
	swap_h_units(lunit);
      { now h_unitable is as before, temp_h_unitable is initialized }
    end;
  end;


procedure assign_and_clear_unit(lunit: unitnum);
  var
    f: fib;
  begin
    if temp_unitable=nil then halt(-3); {unassigned pointer}
    with unitable^[lunit], f do
      if (letter<>RAM) or (lunit=0) then
	begin
	  unitable^[lunit] := temp_unitable^[lunit];
	  funit := lunit;
	  delay_timer(1000); { Fix for SRM coax configuration }
	  if h_unitable <> nil then
	    h_unitable^.tbl[lunit] := temp_h_unitable^.tbl[lunit];
	  call(tm, addr(f), clearunit, lunit, 0, 0);
	  offline := uisblkd and (ioresult<>0);
	end
	else
	  { try to convert old RAM volumes to HFS }
	  install_HFS(lunit, false);
  end;

{----------------------------------------------------------------------}
{
{ set the base_unum fields in h_unitable
{ base_unum is the unit number of the LOWEST unit on this disk
{ e.g., if #11 and #12 share a disk, base_unum for both is 11.
}
procedure set_base_unums;
var
    i,j: unitnum;
begin
    if h_unitable <> nil then with h_unitable^ do
	for i := 1 to maxunit do
	    for j := i+1 to maxunit do
		{ HFS? }
		if tbl[j].is_hfsunit
		{ higher number not yet assigned? }
		and (tbl[j].base_unum = j)
		{ share disk? }
		and on_same_medium(i, j) then
		    tbl[j].base_unum := i;
end;

procedure assign_temp_unitable;
  var
    lunit: unitnum;
    i: integer;
  begin
    if temp_unitable=nil then halt(-3);  {unassigned pointer}
    lockfiles;  {close all standard system files}
    for lunit := 0 to maxunit do
      assign_and_clear_unit(lunit);
    set_base_unums;
    { configure HFS cache }
    if h_unitable <> nil then begin
      call(h_unitable^.config_cache_proc);
    end;

  end;


function sysunit_ok(system_unit: unitnum): boolean;
  begin
    sysunit := system_unit;
    initsysunit;
    with unitable^[system_unit] do
      sysunit_ok := uisblkd and not offline and (uvid<>'');
  end;


procedure zap_assigned_unit(lunit: unitnum);
  begin
    tea_nounit(lunit);  {zap the temp unitable entry}
    unitable^[lunit] := temp_unitable^[lunit];  {now zap the real one!}
  end;
$page$

function on_same_medium(lun1, lun2: unitnum): boolean;
  var
    uep: ^unitentry;
  begin {on_same_medium}
    uep := addr(unitable^[lun2]);
    with unitable^[lun1] do
      on_same_medium := (sc=uep^.sc) and (ba=uep^.ba) and
			(du=uep^.du) and (dv=uep^.dv) and
			(letter=uep^.letter) and (letter<>'R');
  end; {on_same_medium}


procedure remove_extraneous_volumes(first_lun, last_lun: unitnum);
  var
    first_lun_ok: boolean;
    lun: unitnum;
  begin {remove_extraneous_volumes}
    first_lun_ok := false;
    while first_lun<last_lun do
      if first_lun_ok then
	begin
	  lun := first_lun+1;
	  with unitable^[first_lun] do
	    while (lun<=last_lun) and not sysunit_ok(lun) do
	      begin
		if unitable^[lun].byteoffset = byteoffset+umaxbytes then
		  begin
		    umaxbytes := umaxbytes+unitable^[lun].umaxbytes;
		    zap_assigned_unit(lun);
		  end;
		lun := lun+1;
	      end;  {while}
	  first_lun := lun;
	end {then}
      else if sysunit_ok(first_lun) then
	first_lun_ok := true
      else
	first_lun := first_lun+1;
  end; {remove_extraneous_volumes}

end; {ctr}
$page$

module BRstuff;  {BOOTROM stuff}

  (********************************************)
  (*                                          *)
  (*               Warning:                   *)
  (*   This module should not be modified!    *)
  (*                                          *)
  (********************************************)

import
  sysglobals, options, ctr;

export
  const
    INTERNAL_MSUS = MSUS_type
      [ flpy_flags: assign_neither_flpy_unit, letter: INTERNAL,
	dav: dav_type[sc: -1, ba: -1, du:  0, dv: -1] ];

  function internal_mini_present: boolean;
  procedure get_bootdevice_MSUS(var MSUS: MSUS_type);

implement {BRstuff}

type
  signed4     = -8..7;
  signed8     = -128..127;

  fmt_type =  {format field in the msus byte}
    (f0,f1,f2,f3,f4,f5,f6,f7);

  dev_type =  {device field in the msus byte}
    ( d0, d1, d2, d3, d4, d5, d6, d7, d8, d9,d10,d11,d12,d13,d14,d15,
     d16,d17,d18,d19,d20,d21,d22,d23,d24,d25,d26,d27,d28,d29,d30,d31);

  BR_msus_type = {BOOTROM's mass storage unit specifier}
    packed record case boolean of
      false:  {8-bit unit number}
	( fmt: fmt_type;  {directory format}
	  dev: dev_type;  {device}
	  un: signed8;    {8-bit unit number}
	  sc: signed8;    {select code}
	  ba: signed8     {bus address}  );
      true:  {4-bit volume / 4-bit unit number for CS80 & 7905/06 discs}
	( pad: signed8;   {format/device byte}
	  vn4: signed4;   {4-bit volume number}
	  un4: signed4;   {4-bit unit number}  );
    end; {BR_msus_type}

var
  ROM_ID[16382]:  {BOOTROM identification word}
    shortint;

  ndrives[-296]:  {Maximum Unit for Internal Mini-Floppy}
    packed record  b: signed8;  end;

  default_msus[-292]:  {boot device's msus}
    BR_msus_type;
$page$

function internal_mini_present: boolean;
  begin
    if ROM_ID<0
      then internal_mini_present := true            {1.0 BOOTROM on 9826}
      else internal_mini_present := ndrives.b<>-1;  {2.0 or greater BOOTROM}
  end;


procedure get_bootdevice_MSUS(var MSUS: MSUS_type);
  type
    letter_table_type = array[dev_type] of char;
  const
    letter_table =  {BOOTROM dev to Pascal letter conversion table}
      letter_table_type
	[ INTERNAL, NODEVICE, NODEVICE, NODEVICE, HP9895,   HP8290X,  HP9885,   HP913X_A,
{INTERNAL ONLY BEGIN}
	  HP913X_B, HP913X_C, HP7905,   HP7906,   HP7920,   HP7925,   SCSI,     NODEVICE, {DEW - added SCSI}
{EXTERNAL VERSION
	  HP913X_B, HP913X_C, NODEVICE, NODEVICE, NODEVICE, NODEVICE, SCSI,     NODEVICE, {DEW - added SCSI}
{INTERNAL ONLY END}
	  CS80,     CS80,     NODEVICE, NODEVICE, NODEVICE, NODEVICE, BUBBLE  , NODEVICE,
	  NODEVICE, NODEVICE, NODEVICE, NODEVICE, NODEVICE, NODEVICE, NODEVICE, NODEVICE  ];
  begin
    if ROM_ID<0 then  {1.0 Boot ROM on 9826; internal minifloppy only}
      MSUS := INTERNAL_MSUS
    else  {2.0 or greater Boot ROM}
      with default_msus do
	begin
	  if fmt=f7 then  {non sector-oriented device}
	    if (dev=d1) OR (dev=d2)    {added dev=d2 to allow LANSRM. DEW/RDQ/SFB - 5/5/89}
	      then MSUS.letter := SRM
	      else MSUS.letter := NODEVICE
	  else  {sector-oriented device}
	    MSUS.letter := letter_table[dev];
	  MSUS.dav.sc := sc;
	  MSUS.dav.ba := ba;
{INTERNAL ONLY BEGIN}
	  if MSUS.letter in [HP7905, HP7906, CS80, SCSI] then   {DEW 09/89 - added SCSI support}
{EXTERNAL VERSION
	  if MSUS.letter in [CS80, SCSI] then                   {DEW 09/89 - added SCSI support}
{INTERNAL ONLY END}
	    begin
	      MSUS.dav.du := un4;
	      MSUS.dav.dv := vn4;
	    end  {then}
	  else
	    begin
	      MSUS.dav.du := un;
	      MSUS.dav.dv := 0;
	    end;  {else}
	end; {with}
  end;

end; {BRstuff}
$page$

module scanstuff;

  (********************************************)
  (*                                          *)
  (*               Warning:                   *)
  (*   This module should not be modified!    *)
  (*                                          *)
  (********************************************)

import
  sysglobals, options, ctr;

export

  procedure init_scanstuff;
  function scanneddevice_letter(scan_dav: dav_type): char;
  procedure get_CS80_parms(CS80dav: dav_type;
			   var CS80dt: byte; var CS80id: integer;
			   var CS80hardvols: shortint; var CS80mp: mp_type);

implement {scanstuff}


type
  uep_type = ^unitentry;

  uep_proc_type = procedure(uep: uep_type);
  HPIBget_amigo_ident_type = procedure(uep: uep_type; var ident: shortint);
  get_letter_type = procedure(uep: uep_type; ident: shortint; var letter: char);
  get_CS80_parms_type = procedure(var CS80dt: byte;
				  var CS80id: integer;
				  var CS80hardvols: shortint;
				  var CS80mp: mp_type);

  proc_type =
    packed record case integer of
      0: (value, slink: integer);
      1: (up: uep_proc_type);
      2: (gai: HPIBget_amigo_ident_type);
      3: (gl: get_letter_type);
      4: (gcp: get_CS80_parms_type);
    end;


var
  allocate_bkgnd_info_proc: proc_type;
  deallocate_bkgnd_info_proc: proc_type;
  abort_bkgnd_process_proc: proc_type;
  HPIBcheck_sc_proc: proc_type;
  HPIBget_amigo_ident_proc: proc_type;

  get_amigo_letter_proc: proc_type;
  get_CS80_letter_proc: proc_type;
  get_CS80_parms_proc: proc_type;

  bkgnd_and_dischpib_present: boolean;
$page$

function scanneddevice_letter(scan_dav: dav_type): char;

  type
    amigo_class_type = {upper three bits of the first ident byte}
      (storage, display, data_communication, processor,
       stimulus, mesasurement, unassigned6, unassigned7);

  var
    ue: unitentry;
    ident:
      packed record case integer of
	0: (word: shortint);
	1: (upper_byte, lower_byte: byte);
	2: (amigo_class: amigo_class_type);
      end;

  procedure set_scanneddevice_letter(get_letter_proc: proc_type);
    var
      device_letter: char;
    begin {set_scanneddevice_letter}
      if get_letter_proc.value<>0 then
	begin
	  call(get_letter_proc.gl, addr(ue), ident.word, device_letter);
	  scanneddevice_letter := device_letter;
	end; {if}
    end; {set_scanneddevice_letter}

  begin {scanneddevice_letter}
    scanneddevice_letter := NODEVICE;  {until proven otherwise}
    if bkgnd_and_dischpib_present then
      try
	ue.sc := scan_dav.sc;
	ue.ba := scan_dav.ba;
	ue.du := scan_dav.du;
	ue.dv := scan_dav.dv;
	call(allocate_bkgnd_info_proc.up, addr(ue));
	call(HPIBcheck_sc_proc.up, addr(ue));
	call(HPIBget_amigo_ident_proc.gai, addr(ue), ident.word);
	if ident.amigo_class=storage then
	    if ident.upper_byte=2
	      then set_scanneddevice_letter(get_CS80_letter_proc)
	      else set_scanneddevice_letter(get_amigo_letter_proc)
	else if ident.amigo_class=display then
	    scanneddevice_letter := PRINTER;
	call(deallocate_bkgnd_info_proc.up, addr(ue));
      recover
	call(abort_bkgnd_process_proc.up, addr(ue));
  end; {scanneddevice_letter}
$page$

procedure get_CS80_parms(CS80dav: dav_type;
			 var CS80dt: byte; var CS80id: integer;
			 var CS80hardvols: shortint; var CS80mp: mp_type);
  begin {get_CS80_parms}
    if (scanneddevice_letter(CS80dav)=CS80) and (get_CS80_parms_proc.value<>0) then
      call(get_CS80_parms_proc.gcp, CS80dt, CS80id, CS80hardvols, CS80mp)
    else
      begin
	CS80dt := 255;
	CS80id := 0;
	CS80hardvols := 0;
	CS80mp := medium_parameters(NODEVICE);
      end; {else}
  end; {get_CS80_parms}


procedure init_scanstuff;
  {
    NOTE: all procedure variables are GLOBAL, so their static links are
	  guaranteed to have been cleared @@ load time
  }
  begin {init_scanstuff}
    allocate_bkgnd_info_proc.value   := value('BKGND_ALLOCATE_BKGND_INFO');
    deallocate_bkgnd_info_proc.value := value('BKGND_DEALLOCATE_BKGND_INFO');
    abort_bkgnd_process_proc.value   := value('BKGND_ABORT_BKGND_PROCESS');
    HPIBcheck_sc_proc.value          := value('DISCHPIB_HPIBCHECK_SC');
    HPIBget_amigo_ident_proc.value   := value('DISCHPIB_HPIBGET_AMIGO_IDENT');

    get_amigo_letter_proc.value      := value('AMIGODVR_GET_LETTER');
    get_CS80_letter_proc.value       := value('CS80DVR_GET_LETTER');
    get_CS80_parms_proc.value        := value('CS80DVR_GET_PARMS');

    bkgnd_and_dischpib_present := (allocate_bkgnd_info_proc.value<>0) and
				  (deallocate_bkgnd_info_proc.value<>0) and
				  (abort_bkgnd_process_proc.value<>0) and
				  (HPIBcheck_sc_proc.value<>0) and
				  (HPIBget_amigo_ident_proc.value<>0);
  end; {init_scanstuff}


end; {scanstuff}
$page$

module SCSIscanstuff;           {DEW 09/89 - added SCSI support}

  (********************************************)
  (*                                          *)
  (*               Warning:                   *)
  (*   This module should not be modified!    *)
  (*                                          *)
  (********************************************)


import sysglobals, asm, options, ctr;

export
	procedure init_SCSIscanstuff;
	function SCSIscanneddevice_letter(scan_dav: dav_type): char;
	procedure get_SCSI_parms(    SCSIdav:dav_type;
				 var SCSIdt:byte;
				 var SCSIRemovable:boolean;
				 var SCSImp:mp_type);


implement

type
	uep_type = ^unitentry;

	IsScsiCardType          = procedure(    sc:byte;
					    var yes:boolean);
	ScsiSBSizeType          = procedure(var size:integer);
	ScsiSBInitType          = procedure(    pSB:ANYPTR;  pUP:uep_type);
	ScsiCheckDevType        = procedure(    pSB:ANYPTR);
	ScsiDevInfoType         = procedure(    pSB:ANYPTR;
					    var DevType, AnsiVersion:integer;
					    var Removable:boolean;
					    var VendorString:String255);
	ScsiDiscSizeType        = procedure(    pSB:ANYPTR;
					    var NumBytesBlock, NumBlocksTrack,
						NumTracksCylinder, NumCylinders:integer);
	ScsiPreventType         = procedure(    pSB:ANYPTR);

	ScsiProcType            = packed record case integer of
						0:(value, slink:integer);
						1:(IsCard:IsScsiCardType);
						2:(SBSize:ScsiSBSizeType);
						3:(SBInit:ScsiSBInitType);
						4:(CheckDev:ScsiCheckDevType);
						5:(DevInfo:ScsiDevInfoType);
						6:(DiscSize:ScsiDiscSizeType);
						7:(Prevent:ScsiPreventType);
				  end;

var
	IsScsiCardProc,
	ScsiSBSizeProc,
	ScsiSBInitProc,
	ScsiCheckDevProc,
	ScsiDevInfoProc,
	ShowMcBethProc, { JWH 6/93 }
	ScsiDiscSizeProc,
	ScsiPreventProc:ScsiProcType;

	pSB:ANYPTR;
	pUnit:uep_type;
	SCSILIBinMemory:boolean;


procedure init_SCSIscanstuff;
var
	i:integer;
begin
	IsScsiCardProc.value            := value('SCSILIB_ISSCSICARD');
	ScsiSBSizeProc.value            := value('SCSILIB_SCSISBSIZE');
	ScsiSBInitProc.value            := value('SCSILIB_SCSISBINIT');
	ScsiCheckDevProc.value          := value('SCSILIB_SCSICHECKDEV');
	ScsiDevInfoProc.value           := value('SCSILIB_SCSIDEVINFO');
	ScsiDiscSizeProc.value          := value('SCSILIB_SCSIDISCSIZE');
	ScsiPreventProc.value           := value('SCSILIB_SCSIDISCPREVENT');
	{ JWH 6/93 : }
	ShowMcBethProc.value            := value('SCSILIB_CONFIGUREMCBETH');

	SCSILIBinMemory :=      (IsScsiCardProc.value <> 0) and
				(ScsiSBSizeProc.value <> 0) and
				(ScsiSBInitProc.value <> 0) and
				(ScsiCheckDevProc.value <> 0) and
				(ScsiDevInfoProc.value <> 0) and
				(ScsiDiscSizeProc.value <> 0) and
				(ScsiPreventProc.value <> 0);

	if SCSILIBinMemory then
	begin
		call(ScsiSBSizeProc.SBSize, i);
		newbytes(pSB, i);
		newbytes(pUnit, sizeof(unitentry));
	end;
end;

procedure SetUnit(pUnit:uep_type; dav:dav_type);
begin
	with pUnit^ do
	begin
		sc := dav.sc;
		ba := dav.ba;
		du := dav.du;
		dv := dav.dv;
	end;
end;

function SCSIscanneddevice_letter(scan_dav: dav_type): char;
var
	b:boolean;
begin
	SCSIscanneddevice_letter := NODEVICE;  {until proven otherwise}
	if SCSILIBinMemory then
	begin
		call(IsScsiCardProc.IsCard, scan_dav.sc, b);
		if b then {this is a scsi card}
		begin
			SetUnit(pUnit, scan_dav);
			call(ScsiSBInitProc.SBInit, pSB, addr(scan_dav));
			call(ScsiCheckDevProc.CheckDev, pSB);
			if (ioresult = ord(inoerror)) or
			   (ioresult = ord(zmediumchanged)) or
			   (ioresult = ord(znotready)) then
				SCSIscanneddevice_letter := SCSI;
			ioresult := ord(inoerror);
		end;
	end;
end;


{ JWH 6/93 }
procedure get_SCSI_tape_parms(    SCSIdav:dav_type;
			 var SCSIdt:byte;
			 var SCSIRemovable:boolean;
			 var SCSImp:mp_type);
begin
	SCSIdt := 1; { sequential access type }
	SCSIRemovable := TRUE;
end;

{ JWH 6/93 (modified slightly) }
procedure get_SCSI_parms(    SCSIdav:dav_type;
			 var SCSIdt:byte;
			 var SCSIRemovable:boolean;
			 var SCSImp:mp_type);
label   1,2; { <===== JWH added label 2 }
var
	dt, ansi:integer;
	s:string255;
	nbps, nspt, ntpc, nc:integer;
	DoPrevent:boolean;
begin
	DoPrevent := FALSE;
	if SCSIscanneddevice_letter(SCSIdav) = SCSI then
	begin
		call(ScsiDevInfoProc.DevInfo, pSB, dt, ansi, SCSIRemovable, s);

		{ JWH 6/93 : }
		if (dt = 1) then { sequential device }
		 begin
		  if ShowMcBethProc.value <> 0 then
		    call(ShowMcBethProc.CheckDev,pSB);
		  SCSIdt := 1;
		  goto 2;
		 end;


		if (ioresult <> ord(inoerror)) or ((dt <> 0) and (dt <> 1))
		   then
		    {error on communication or not a disk or tape type}
			goto 1;
		SCSIdt := dt;
		if (SCSIRemovable) and (SCSIRemovableOption = AllAreHard)
		 and (dt <> 1) { <======= JWH 6/93 }
		  then
		begin
			SCSIRemovable := FALSE;
			DoPrevent := TRUE;
		end;
		call(ScsiDiscSizeProc.DiscSize, pSB,
		   nbps, nspt, ntpc, nc);
		if ioresult = ord(inoerror) then
		begin
			SCSImp.tpm := ntpc * nc;
			SCSImp.bpt := nbps * nspt;
			if (SCSIRemovable) and
			   (SCSIRemovableOption = AllOver10MAreHard) and
			   ( (SCSImp.tpm * SCSImp.bpt) >= hex('A00000') ) then
			begin
				SCSIRemovable := FALSE;
				DoPrevent := TRUE;
			end;
		end
		else if SCSIRemovable then
		begin
			ioresult := ord(inoerror);
			SCSImp.tpm := 1;
			SCSImp.bpt := 256;
		end
		else
			goto 1;
	end
	else
	begin
		1:
		ioresult := ord(inoerror);
		DoPrevent := FALSE;
		SCSIdt := 255;
		SCSImp.tpm := 0;
		SCSImp.bpt := 0;
	end;
     2:  { <========= JWH 6/93 }
	if (DoPrevent) then
	begin
		call(ScsiPreventProc.Prevent, pSB);
		ioresult := ord(inoerror);
	end;
end;


end; {SCSIscanstuff}
$page$

{program ctable}

  (********************************************)
  (*               Caution:                   *)
  (* Modify this section only if the desired  *)
  (* configuration cannot be achieved by      *)
  (* modifying the OPTIONS module.            *)
  (********************************************)

import
  sysglobals, fs, ldr, options, ctr, BRstuff, scanstuff, SCSIscanstuff, bootDAMmodule;  {DEW - added SCSI}

const
  sysprefix = '/WORKSTATIONS/SYSTEM';
  null_dav =
    dav_type[sc: -1, ba: -1, du: -1, dv: -1];
  null_MSUS =
    MSUS_type[flpy_flags: assign_neither_flpy_unit, letter: NODEVICE, dav: null_dav];
  HP9885_default_MSUS =
    MSUS_type[flpy_flags: assign_neither_flpy_unit, letter: HP9885, dav: HP9885_default_dav];
  MSUS_array_size = 10;

type
  MSUS_array_type = array [1..MSUS_array_size] of MSUS_type;
  log_MSUS_options = (search_for_other_units, do_not_search_for_other_units);

var
  flpy_MSUS: MSUS_array_type;
  harddisc_MSUS: MSUS_array_type;
  CS80tape_MSUS: MSUS_array_type;
  SCSItape_MSUS: MSUS_array_type; { JWH 6/93 }
  scanner_MSUS: MSUS_type;

  local_printer_dav: dav_type;
  SRM_dav: dav_type;
  BUBBLE_dav: dav_type;

  index, select_code, bus_address, i, nvols: shortint; {LAF 870622}
  lun, lun1, lun2: unitnum;
  CS80dt: byte;
  CS80id: integer;
  CS80hardvols: shortint;
  SCSIdt: byte;
  SCSIRemovable:boolean;
  mp: mp_type;
  pp: pp_type;
  ok: boolean;



function increment_and_test_lun: boolean;
  begin {increment_and_test_lun}
    lun := lun+1;
    increment_and_test_lun := lun<=last_harddisc_lun;
  end; {increment_and_test_lun}
$page$

function unit_prefix_successful(dirname: fid): boolean;
  var
    unitnum: integer;
    kvid: vid;
  begin {unit_prefix_successful}
    doprefix(dirname, kvid, unitnum, true);
    unit_prefix_successful := ioresult=ord(inoerror);
  end; {unit_prefix_successful}


procedure zero_out_NA_fields(var device_MSUS: MSUS_type);
  const
    clear = true;
    retain = false;
  procedure zero_fields(sc, ba, du, dv: boolean);
    begin  {zero_fields}
      if sc then device_MSUS.dav.sc := 0;
      if ba then device_MSUS.dav.ba := 0;
      if du then device_MSUS.dav.du := 0;
      if dv then device_MSUS.dav.dv := 0;
    end;  {zero_fields}
  begin {zero_out_NA_fields}
    case device_MSUS.letter of
      INTERNAL:
	zero_fields({sc} clear , {ba} clear , {du} retain, {dv} clear );
      HP9885:
	zero_fields({sc} retain, {ba} clear , {du} retain, {dv} clear );
{INTERNAL ONLY BEGIN}
      HP9895, HP8290X, HP913X_A, HP913X_B, HP913X_C, HP7920, HP7925, SRM:
{EXTERNAL VERSION
      HP9895, HP8290X, HP913X_A, HP913X_B, HP913X_C, SRM:
{INTERNAL ONLY END}
	zero_fields({sc} retain, {ba} retain, {du} retain, {dv} clear );
      BUBBLE:
	zero_fields({sc} retain, {ba} clear , {du} clear , {dv} clear );
      EPROM:
	zero_fields({sc} clear , {ba} clear , {du} clear , {dv} retain);
      otherwise  {includes HP7905, HP7906, CS80, SCSI}
	{do nothing};
    end; {case}
  end; {zero_out_NA_fields}


procedure assign_flpy_unit_pair(lun: unitnum; dam: ds_type; index: shortint);
  begin {assign_flpy_unit_pair}
    with flpy_MSUS[index], flpy_flags, dav do
      begin
	if assign_even_unit then
	  begin
	    tea_flpy(lun, letter, dam, sc, ba, du);
	    lun := lun+1;
	  end; {if}
	if assign_odd_unit then
	  tea_flpy(lun, letter, dam, sc, ba, du+1);
      end; {with}
  end; {assign_flpy_unit_pair}
$page$

procedure log_MSUS(MSUS: MSUS_type; log_MSUS_option: log_MSUS_options);


  type
    log_flpy_MSUS_options = (assign_both_units, assign_only_this_unit);


  procedure log_specific_MSUS(var specific_MSUS: MSUS_array_type);
    var
      index: shortint;
      found: boolean;
    begin {log_specific_MSUS}
      index := 0;
      repeat
	index := index+1;
	found := MSUSs_match(specific_MSUS[index], MSUS);
      until found or (index=MSUS_array_size);
      if found
	then MSUS.flpy_flags := specific_MSUS[index].flpy_flags {preserve}
	else MSUS.flpy_flags := assign_neither_flpy_unit;       {initialize}
      while index>1 do
	begin
	  specific_MSUS[index] := specific_MSUS[index-1];
	  index := index-1;
	end;  {while}
      specific_MSUS[1] := MSUS;
    end; {log_specific_MSUS}


  procedure log_flpy_MSUS(log_flpy_MSUS_option: log_flpy_MSUS_options);
    var
      odd_unit: boolean;
    begin {log_flpy_MSUS}
      with MSUS.dav do
	begin  {since floppy units are assigned in pairs...}
	  odd_unit := odd(du);     {remember which unit this actually is...}
	  du := du-ord(odd_unit);  {but log only the even-numbered unit!}
	end; {with}
      log_specific_MSUS(flpy_MSUS);
      with flpy_MSUS[1] do  {update the flpy_flags}
	if log_flpy_MSUS_option=assign_both_units then
	  flpy_flags := assign_both_flpy_units
	else  {set only this unit's assignment flag}
	  if odd_unit
	    then flpy_flags.assign_odd_unit  := true
	    else flpy_flags.assign_even_unit := true;
    end; {log_flpy_MSUS}


  procedure log_harddisc_MSUS;
    begin {log_harddisc_MSUS}
      MSUS.dav.dv := 0;  {all vols will be assigned, so log only volume zero}
      log_specific_MSUS(harddisc_MSUS);
    end; {log_harddisc_MSUS}
$page$

  function any_9895_unit_missing: boolean;
    var
      temp_dav: dav_type;
      unit_missing: boolean;
    begin {any_9895_unit_missing}
      temp_dav := MSUS.dav;
      temp_dav.du := 3;  {start with unit 3 and work down}
      repeat  {see if all four units are present}
	unit_missing := scanneddevice_letter(temp_dav)<>HP9895;
	temp_dav.du := temp_dav.du-1;
      until (temp_dav.du<0) or unit_missing;
      any_9895_unit_missing := unit_missing;
    end; {any_9895_unit_missing}


  procedure search_higher_numbered_CS80_units;
    var
      temp_MSUS: MSUS_type;
    begin {search_higher_numbered_CS80_units}
      temp_MSUS := MSUS;
      with temp_MSUS, dav do
	if du<14 then  {potentially there are higher-numbered units}
	  begin
	    du := du+1;
	    dv := 0;  {always look for volume 0}
	    letter := scanneddevice_letter(dav);
	    log_MSUS(temp_MSUS, search_for_other_units);  {recurse!}
	  end; {if}
    end; {search_higher_numbered_CS80_units}


  procedure log_CS80_MSUS;
    var
      CS80dt: byte;             {device type}
      CS80id: integer;          {HP product number}
      CS80hardvols: shortint;   {number of volumes}
      CS80mp: mp_type;          {media parameters}
    const
      tape_dt = 2;
      min_hd_size = 10000000;  {bytes}
    begin {log_CS80_MSUS}
      get_CS80_parms(MSUS.dav, CS80dt, CS80id, CS80hardvols, CS80mp);
      if CS80dt=tape_dt then
	log_specific_MSUS(CS80tape_MSUS)
      else if (CS80hardvols=1) and (CS80mp.bpt*CS80mp.tpm<min_hd_size) then
	log_flpy_MSUS(assign_only_this_unit)
      else
	log_harddisc_MSUS;
    end; {log_CS80_MSUS}

  procedure search_higher_numbered_SCSI_units;          {DEW 09/89 - added SCSI support}
    var
      temp_MSUS: MSUS_type;
    begin {search_higher_numbered_SCSI_units}
      {
	search for multiple logical units on a given bus address
      }
      temp_MSUS := MSUS;
      with temp_MSUS, dav do
	if du<7 then
	  begin
	    du := du+1;
	    dv := 0;  {always look for volume 0}
	    letter := SCSIscanneddevice_letter(dav);
	    log_MSUS(temp_MSUS, search_for_other_units);  {recurse!}
	  end; {if}
    end; {search_higher_numbered_SCSI_units}


  procedure log_SCSI_MSUS;                              {DEW 09/89 - added SCSI support}
    var
      SCSIdt: byte;             {device type}
      SCSIRemovable: boolean;   {removable disk}
      SCSImp: mp_type;          {media parameters}
    begin {log_SCSI_MSUS}
      get_SCSI_parms(MSUS.dav, SCSIdt, SCSIRemovable, SCSImp);
      if SCSIdt = 0 then {disk type}
      begin
	if SCSIRemovable then
	  log_flpy_MSUS(assign_only_this_unit)
	else
	  log_harddisc_MSUS;
      end;

      if SCSIdt = 1 then {tape type} { <====== JWH 6/93 }
      begin
	log_specific_MSUS(SCSItape_MSUS)
      end;


      {
	else printers, etc. not supported.
      }
    end; {log_SCSI_MSUS}
$page$

  begin {log_MSUS}

    zero_out_NA_fields(MSUS);

    case MSUS.letter of

      INTERNAL, HP8290X, HP9885:
	log_flpy_MSUS(assign_both_units);

{INTERNAL ONLY BEGIN}
      HP913X_A, HP913X_B, HP913X_C, HP7905, HP7906, HP7920, HP7925:
{EXTERNAL VERSION
      HP913X_A, HP913X_B, HP913X_C:
{INTERNAL ONLY END}
	log_harddisc_MSUS;

      HP9895:
	if any_9895_unit_missing then  {ultimately assign only two units }
	  log_flpy_MSUS(assign_both_units)
	else  {ultimately assign all four units (probably a 913X)}
	  begin
	    MSUS.dav.du := 0;  {log only unit zero}
	    log_harddisc_MSUS;
	  end;  {else}

      CS80:
	begin
	  if log_MSUS_option=search_for_other_units then
	    search_higher_numbered_CS80_units;
	  log_CS80_MSUS;  {distinguishes tapes, floppies, & hard discs!}
	end;

      SRM:
	SRM_dav := MSUS.dav;

      PRINTER:
	local_printer_dav := MSUS.dav;

      BUBBLE:
	BUBBLE_dav := MSUS.dav;

      SCSI:                                             {DEW 09/89 - added SCSI support}
	begin
	  if log_MSUS_option=search_for_other_units then
	    search_higher_numbered_SCSI_units;
	  log_SCSI_MSUS;  {only some tapes (JWH 6/93) disks are
			   supported right now}
	end;

      otherwise
	{do nothing};

    end; {case}

  end; {log_MSUS}
$page$

{
{ Return the suffix of the system we booted.
{ e.g. SYSTEM_xxx -> xxx
{      SYSxxxxxxx -> xxxxxxx
{ Used as suffix for sysprefix (/WORKSTATIONS/SYSTEM) when
{ setting system volume on HFS disks.
}
function syssuffix: string20;
begin
  syssuffix := bootname('', 0);
end;


{
{ determine whether a card at specified select code is 98629--SRM
{ added 870622 LAF to fix bug FSDat01185
{
{ added ability to connect up to SRMLAN support, if it exists and is
{ willing to support 98643A at select code sc. is_SRMcard will return
{ TRUE if it's SRM card, or 98643A with SRMLAN support. SFB/RDQ 1/19/89
}
function is_SRMcard(sc: integer): boolean;
const
  srmlan_symbol='LANSRM_LANSRM_OK';     {procedure in SRMLAN version of SRM}
type
  chararray = packed array [0..65535] of char;
  pchararray = ^chararray;
  proctrick_rectype = record case boolean of
	true  : (proc:procedure(var sc : integer));
	false : (entry, statlink: integer);
    end;
var
  card: pchararray;
  stat2addr: integer;
  kludgerec: record case integer of
    0: (int: integer);
    1: (adr: pchararray);
    end;
  proctrick : proctrick_rectype;
begin
try     (* recover if no card here or if not SRM *)
  is_SRMcard:=true;
  kludgerec.int := sc * hex('10000') + hex('600000');   (* card address *)
  card := kludgerec.adr;
  if ord(card^[1]) mod 128 = 52 then        (* datacomm ?? *)
    begin
      stat2addr := ord(card^[16395])*256 + ord(card^[16393]);
      if stat2addr >= 32768 then escape(0);
      if ord(card^[stat2addr*2+1]) mod 128 <> 1 then escape(0); (* not datacomm *)
      if ord(card^[hex('402f')]) <> 3 then escape(0);       (* not SRM *)
    end
  else
    begin
      proctrick.statlink:=0;
      proctrick.entry:=value(SRMLAN_SYMBOL);
      if proctrick.entry <> 0 then
	call(proctrick.proc, sc);       {SRMLAN_OK will set sc < 0 if will support
					 SRMLAN for this card.
					 Let SRMLAN_OK decide if card is 98643A}
      if sc >= 0 then escape(0);        {LANSRM will not support this sc}
    end;
recover
  is_SRMcard := false;
end;


begin {ctable}

  { various initializations }

  call(cleariohook); {init IO cards in case the BOOTROM drivers touched them}

  init_scanstuff;
  init_SCSIscanstuff;

  for index := 1 to MSUS_array_size do
    begin
      flpy_MSUS[index]     := null_MSUS;
      harddisc_MSUS[index] := null_MSUS;
      CS80tape_MSUS[index] := null_MSUS;
      SCSItape_MSUS[index] := null_MSUS; { JWH 6/93 }
    end;  {for}

  SRM_dav                  := SRM_default_dav;     {overridden if bootdevice}

  BUBBLE_dav               := BUBBLE_default_dav;  {overridden if bootdevice}

  if local_printer_option=HPIB
    then local_printer_dav := local_HPIB_printer_default_dav   {scan may override}
    else if local_printer_option=RS232
    then local_printer_dav := local_RS232_printer_default_dav  {scan may override}
    else local_printer_dav := local_PARALLEL_printer_default_dav;  {scan may override}


  { log the default 9885 floppy pair, since HP-IB scanning won't include it }

  log_MSUS(HP9885_default_MSUS, search_for_other_units);


  { scan the HP-IB's for mass storage devices and possibly a local printer }

  with scanner_MSUS, dav do
    for index := 1 to sc_list_length do
      for bus_address := 0 to 7 do
	begin
	  sc := sc_list[index];
	  ba := bus_address;
	  du := 0;
	  dv := 0;
	  letter := scanneddevice_letter(dav);
	  log_MSUS(scanner_MSUS, search_for_other_units);
	end; {for}

  { scan the SCSI select codes for disks}

  with scanner_MSUS, dav do
    for index := 1 to SCSIsc_list_length do
      for bus_address := 0 to 7 do
	begin
	  sc := SCSIsc_list[index];
	  ba := bus_address;
	  du := 0;
	  dv := 0;
	  letter := SCSIscanneddevice_letter(dav);
	  log_MSUS(scanner_MSUS, search_for_other_units);
	end; {for}


  { log internal mini if present, since HP-IB scanning didn't include it }

  if internal_mini_present then
    log_MSUS(INTERNAL_MSUS, search_for_other_units);


  { check sc 21 for SRM, scan for it if it's not there, keep lowest sc }
  { added 870622 LAF to fix bug FSDat01185 }

  if not is_SRMcard(SRM_dav.sc) then
    for select_code:=31 downto 7 do
      if is_SRMcard(select_code) then
	SRM_dav.sc:=select_code;


  { get the bootdevice MSUS & log it }

  get_bootdevice_MSUS(bootdev_MSUS);
  zero_out_NA_fields(bootdev_MSUS);  {for tea routine comparisons}
  log_MSUS(bootdev_MSUS, do_not_search_for_other_units);
  bootdev_lun := 0;  {set otherwise if/when bootdevice is assigned in tea}
$page$

  { Create a temporary table & fill it with dummy entries }

  create_temp_unitable;


  { standard assignments: avoid changing }

  tea_memory_volume_dam(primary_dam);

  tea_crt( 1);
  tea_kbd( 2);

  assign_flpy_unit_pair( 3, primary_dam, {flpy_MSUS[]} 1);

  with SRM_dav do
    tea_srm( 5, sc, ba, du);

  with local_printer_dav do
    tea_local_printer( 6, sc, ba, {uvid} 'PRINTER', local_printer_timeout);


  { optional floppy unit pairs }

  for index := 2 to floppy_unit_pairs do
    assign_flpy_unit_pair(7+(index-2)*2, primary_dam, {flpy_MSUS[]} index);

$page$

  { local hard discs }

  $if true$

    lun := first_harddisc_lun-1;

    for index := 1 to MSUS_array_size do
      with harddisc_MSUS[index], dav do
	case letter of

	  HP9895: {9895 ident with all four units present; probably a HP913X}
	    for i := 0 to 3 do
	      if increment_and_test_lun then
		tea_HP9895(lun, primary_dam, sc, ba, {du} i, {block_offset} 0);

{INTERNAL ONLY BEGIN}
	  HP913X_A, HP913X_B, HP913X_C, HP7920, HP7925:
{EXTERNAL VERSION
	  HP913X_A, HP913X_B, HP913X_C:
{INTERNAL ONLY END}
	    begin
	      mp := medium_parameters(letter);
	      pp := partitioning_parameters(letter);
	      nvols := number_vols(mp, pp);
	      hfs_installed := false;
	      for i := 0 to nvols-1 do
		if not hfs_installed and increment_and_test_lun then
		  tea_amigo_sv(lun, primary_dam, sc, ba, du,
				    vol_offset(i, nvols, mp),
				    letter,
				    vol_bytes(i, nvols, mp));
	    end;

{INTERNAL ONLY BEGIN}
	  HP7905, HP7906:
	    begin
	      mp := medium_parameters(letter);
	      pp := partitioning_parameters(letter);
	      repeat
		nvols := number_vols(mp, pp);
		hfs_installed := false;
		for i := 0 to nvols-1 do
		  if not hfs_installed and increment_and_test_lun then
		    tea_amigo_mv(lun, primary_dam, sc, ba, du, dv,
				      vol_offset(i, nvols, mp),
				      letter,
				      vol_bytes(i, nvols, mp));
		if letter=HP7905 then  {adjust for its half-size fixed portion}
		  mp.tpm := mp.tpm div 2;
		dv := dv+1;
	      until dv>=2;
	    end;
{INTERNAL ONLY END}

	  CS80:
	    begin
	      pp := partitioning_parameters(letter);
	      repeat
		get_CS80_parms(dav, CS80dt, CS80id, CS80hardvols, mp);
		if mp.tpm=1 then  {track partitioning info unavailable...}
		  mp := block_boundaries(mp);  {will have to fake it!}
		nvols := number_vols(mp, pp);
		hfs_installed := false;
		for i := 0 to nvols-1 do
		  if not hfs_installed and increment_and_test_lun then
		    tea_CS80_mv(lun, primary_dam, sc, ba, du, dv,
				     vol_offset(i, nvols, mp),
				     {devid} CS80id,
				     vol_bytes(i, nvols, mp),
				     mp.tpm*mp.bpt);
		dv := dv+1;
	      until dv>=CS80hardvols;
	    end;

	  SCSI:
	    begin
		pp := partitioning_parameters(letter);
		get_SCSI_parms(dav, SCSIdt, SCSIRemovable, mp);
		nvols := number_vols(mp, pp);
		hfs_installed := false;
		for i := 0 to nvols-1 do
		  if not hfs_installed and increment_and_test_lun then
		    tea_SCSI_mv(lun, primary_dam, sc, ba, du, dv,
				     vol_offset(i, nvols, mp),
				     {devid} SCSIdt,
				     vol_bytes(i, nvols, mp),
				     mp.tpm*mp.bpt);
	    end;

	  otherwise
	    {no local hard disc logged};

	end; {case}

  $end$  { local hard discs }


  { CS80 and SCSI (JWH 6/93) tapes }

  $if true$

    with CS80tape_MSUS[1], dav do
      if letter=CS80 then
	tea_CS80_sv(41, LIF_dam, sc, ba, du, dv);

    with CS80tape_MSUS[2], dav do
      if letter=CS80 then
	tea_CS80_sv(42, LIF_dam, sc, ba, du, dv);


    { Put SCSI tape at 41 if nothing else there, else }
    { put it at unit 42. Handled in tea_SCSI_tape JWH 6/93. }

    with SCSItape_MSUS[1], dav do
      if (letter=SCSI) then
	  tea_SCSI_tape(41, LIF_dam, sc, ba, du, dv);


  $end$  { CS80 tapes }


  { secondary directory access method entries for highest priority floppies }

  assign_flpy_unit_pair(43, secondary_dam, {flpy_MSUS[]} 1);

  { secondary directory access method entries for additional floppies }

  assign_flpy_unit_pair(47, secondary_dam, {flpy_MSUS[]} 2);

  assign_flpy_unit_pair(49, secondary_dam, {flpy_MSUS[]} 3);



  { duplicate entries for prefixing down the SRM }

{INTERNAL ONLY BEGIN}
  (***********************************************************************)
  (*  NOTE:  Additional duplicate SRM entries may be assigned here, then *)
  (*    prefixed down below after assigning the temp_unitable.  However  *)
  (*    for correct behavior in assigning the system unit, specifically  *)
  (*    if booting off the SRM, unit #45 must be the assigned AFTER all  *)
  (*    the other SRM units have been assigned!                          *)
  (*                                                                     *)
  (*    You may assign both "real" SRM and SRM-UX units with this code.  *)
  (*    You must put in the correct unit number, select code, bus        *)
  (*    address (really SRM host node number), and du (really SRM disc   *)
  (*    volume number or SRM-UX emulated disc volume number.)            *)
  (*                                                                     *)
  (*    Unit numbers 46 through 50 are often available for use as        *)
  (*    additional SRM or SRM-UX entries, especially if you have no      *)
  (*    more than one floppy unit pair, and you are not booting from an  *)
  (*    HFS hard disc.                                                   *)
  (*                                                                     *)
  (*    SRM volume information is available from the SRM console.        *)
  (*    SRM-UX volume emulation information is available from the        *)
  (*    HP-UX file "/etc/srmconf" on the SRM-UX server machine.          *)
  (***********************************************************************)
{INTERNAL ONLY END}

  with SRM_dav do
    begin
      {  tea_srm(46, sc, ba, du);  {free unless booting from HFS hard disc}
      tea_srm(45, sc, ba, du);  {for possible use as the system unit}
    end; {with}

$page$

  { templates for "manually" specifying mass storage table entry assignments }


  $if false$ { internal minifloppy in a 9826/9836 }
    tea_mini( 3, primary_dam, {du} 0);
    tea_mini( 4, primary_dam, {du} 1);
  $end$

  $if false$ { HP8290X, HP9121, or the floppy in an HP913X }
    tea_HP8290X( 3, primary_dam, {sc}  7, {ba} 0, {du} 0);
    tea_HP8290X( 4, primary_dam, {sc}  7, {ba} 0, {du} 1);
  $end$

  $if false$ { HP9895 }
    tea_HP9895( 7, primary_dam, {sc}  7, {ba} 0, {du} 0, {block_offset} 0);
    tea_HP9895( 8, primary_dam, {sc}  7, {ba} 0, {du} 1, {block_offset} 0);
  $end$

  $if false$ { HP913X (four volume 9895 look-a-like version) }
    for i := 0 to 3 do
      tea_HP9895(11+i, primary_dam, {sc}  7, {ba} 0, {du} i, {block_offset} 0);
  $end$

  $if false$ { HP913X_A (5 Mbyte single volume version) }
    mp := medium_parameters(HP913X_A);
    nvols := 4;
    for i := 0 to nvols-1 do
      tea_amigo_sv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0,
			 vol_offset(i, nvols, mp),
			 HP913X_A,
			 vol_bytes(i, nvols, mp));
  $end$

  $if false$ { HP913X_B (10 Mbyte single volume version) }
    mp := medium_parameters(HP913X_B);
    nvols := 9;
    for i := 0 to nvols-1 do
      tea_amigo_sv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0,
			 vol_offset(i, nvols, mp),
			 HP913X_B,
			 vol_bytes(i, nvols, mp));
  $end$

  $if false$ { HP913X_C (15 Mbyte single volume version) }
    mp := medium_parameters(HP913X_C);
    nvols := 14;
    for i := 0 to nvols-1 do
      tea_amigo_sv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0,
			 vol_offset(i, nvols, mp),
			 HP913X_C,
			 vol_bytes(i, nvols, mp));
  $end$
$page$

{INTERNAL ONLY BEGIN}
  $if false$ { HP7905 }
    mp := medium_parameters(HP7905);
    { mp := block_boundaries(mp);  {override track boundary partitioning}
    nvols := 10;
    for i := 0 to nvols-1 do  {assign removable medium entries}
      tea_amigo_mv (11+i, primary_dam, {sc} 14, {ba} 0, {du} 0, {dv} 0,
			  {offset} vol_offset(i, nvols, mp),
			  {letter} HP7905,
			  {umaxbytes} vol_bytes(i, nvols, mp));
    mp.tpm := mp.tpm div 2;  {fixed only half size}
    nvols := 5;
    for i := 0 to nvols-1 do  {assign fixed medium entries}
      tea_amigo_mv (21+i, primary_dam, {sc} 14, {ba} 0, {du} 0, {dv} 1,
			  {offset} vol_offset(i, nvols, mp),
			  {letter} HP7905,
			  {umaxbytes} vol_bytes(i, nvols, mp));
  $end$

  $if false$ { HP7906 }
    mp := medium_parameters(HP7906);
    { mp := block_boundaries(mp);  {override track boundary partitioning}
    nvols := 10;
    for i := 0 to nvols-1 do  {assign removable medium entries}
      tea_amigo_mv (11+i, primary_dam, {sc} 14, {ba} 0, {du} 0, {dv} 0,
			  {offset} vol_offset(i, nvols, mp),
			  {letter} HP7906,
			  {umaxbytes} vol_bytes(i, nvols, mp));
    for i := 0 to nvols-1 do  {assign fixed medium entries}
      tea_amigo_mv (21+i, primary_dam, {sc} 14, {ba} 0, {du} 0, {dv} 1,
			  {offset} vol_offset(i, nvols, mp),
			  {letter} HP7906,
			  {umaxbytes} vol_bytes(i, nvols, mp));
  $end$

  $if false$ { HP7920 }
    mp := medium_parameters(HP7920);
    { mp := block_boundaries(mp);  {override track boundary partitioning}
    nvols := 30;
    for i := 0 to nvols-1 do
      tea_amigo_sv(11+i, primary_dam, {sc} 14, {ba} 0, {du} 0,
			 {offset} vol_offset(i, nvols, mp),
			 {letter} HP7920,
			 {umaxbytes} vol_bytes(i, nvols, mp));
  $end$

  $if false$ { HP7925 }
    mp := medium_parameters(HP7925);
    { mp := block_boundaries(mp);  {override track boundary partitioning}
    nvols := 30;
    for i := 0 to nvols-1 do
      tea_amigo_sv(11+i, primary_dam, {sc} 14, {ba} 0, {du} 0,
			 {offset} vol_offset(i, nvols, mp),
			 {letter} HP7925,
			 {umaxbytes} vol_bytes(i, nvols, mp));
  $end$
{INTERNAL ONLY END}
$page$

  $if false$ { current CS/80 discs "soft" partitioned by the host }
      CS80id := 7908; nvols := 16; mp.tpm :=  5* 370; mp.bpt := 35*256;  {7908}
    { CS80id := 7911; nvols := 27; mp.tpm :=  3* 572; mp.bpt := 64*256;  {7911}
    { CS80id := 7912; nvols := 30; mp.tpm :=  7* 572; mp.bpt := 64*256;  {7912}
    { CS80id := 7914; nvols := 30; mp.tpm :=  7*1152; mp.bpt := 64*256;  {7914}
    { CS80id := 7933; nvols := 30; mp.tpm := 13*1321; mp.bpt := 92*256;  {7933}
    { CS80id := 7935; nvols := 30; mp.tpm := 13*1321; mp.bpt := 92*256;  {7935}
    { mp := block_boundaries(mp);  {override track boundary partitioning}
    hfs_installed:=false;
    for i := 0 to nvols-1 do
      if not hfs_installed then
	tea_CS80_mv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0, {dv} 0,
			  vol_offset(i, nvols, mp),
			  {devid} CS80id,
			  vol_bytes(i, nvols, mp),
			  mp.tpm*mp.bpt);
  $end$


  $if false$ { current CS/80 discs "hard" partitioned by the device }
      CS80hardvols :=  3;
      for i := 0 to CS80hardvols-1 do
	tea_CS80_sv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0, {dv} i);
  $end$


  $if false$ { Command Set/80 floppy }
    tea_CS80_sv( 3, primary_dam, {sc}  7, {ba} 0, {du} 0, {dv} 0);
  $end$


  $if false$ { Command Set/80 tape }
    tea_CS80_sv(41, LIF_dam, {sc}  7, {ba} 0, {du} 1, {dv} 0);
  $end$


  $if false$ { BUBBLE memory }
    {watch for conflicting uses of unit 42}
    {BUBBLE_DAV.SC default is 30 but may have been changed to boot SC}
    tea_BUBBLE(42,primary_dam,BUBBLE_dav.SC);
  $end$


  $if false$ { EPROM DISC }
    {watch for conflicting uses of unit 42}
    tea_EPROM(42,primary_dam,{ sequence number } 0);
  $end$


  { end of templates }
$page$

  { assign the new unitable and unitclear all units }

  assign_temp_unitable;

  { prefix the primary and secondary SRM unit entries }

  if not unit_prefix_successful('#5:/') then
    {do nothing};  {tries to set up uvid for possible default unit assignment below}

  { if not unit_prefix_successful('#46:/?') then zap_assigned_unit(46);}
  {NOTE: DO NOT UNCOMMENT THE ABOVE LINE IF YOU BOOT FROM AN HFS DISC! }

  if not unit_prefix_successful('#45:'+sysprefix+srmnode(unitable^[45].sc)) then
    if not unit_prefix_successful('#45:'+sysprefix) then
      zap_assigned_unit(45);


  { remove extraneous local hard disc entries if necessary }

  lun2 := first_harddisc_lun;
  while lun2<last_harddisc_lun do
    begin
      lun1 := lun2;
      repeat
	lun2 := lun2+1;
      until (lun2>last_harddisc_lun) or not on_same_medium(lun1, lun2);
      pp := partitioning_parameters(unitable^[lun1].letter);
      if pp.mnv<-1 then
	remove_extraneous_volumes(lun1, lun2-1);
    end; {while}


  { assign the system unit }

  if specified_system_unit<>0 then
    ok := sysunit_ok(specified_system_unit)
  else if (bootdev_lun<>0) and (unitable^[bootdev_lun].umaxbytes>300000) then
    ok := sysunit_ok(bootdev_lun)
  else  {search for a more suitable system unit}
    begin
      index := 0;
      repeat
	index := index+1;
	ok := sysunit_ok(sysunit_list[index]);
      until ok or (index>=sysunit_list_length);
      if not ok then  {revert back to boot device, hoping it was identified}
	ok := sysunit_ok(bootdev_lun);
    end; {else}


  { special case for default unit assignment }

  if sysunit=45 then  {set the default unit to the primary SRM unit entry}
    dkvid := unitable^[5].uvid;
$page$
  { rearrange things for HFS }
  if h_unitable <> nil then with h_unitable^ do begin

      { if booted from HFS, need to reset syvid and dkvid       }
      { also, try to set sysvolume to #46:/WORKSTATIONS/SYSTEM*  }
      if unitable^[sysunit].uisfixed
      and tbl[sysunit].is_hfsunit
      and sysunit_ok(sysunit) then begin
	lun := sysunit;
	extra_HFS_unit(sysunit, 46, sysprefix+syssuffix);
	if not tbl[46].is_hfsunit then
	  extra_HFS_unit(sysunit, 46, sysprefix);
	if tbl[46].is_hfsunit and sysunit_ok(46) then
	  dkvid := unitable^[lun].uvid;
      end;

      { At this point, there is only one HFS unit per disc, except    }
      { on the system disc (if it's HFS), where there are two -- one  }
      { at /WORKSTATIONS/SYSTEM, the other at /.  Add more as         }
      { follows:                                                      }
      { extra_HFS_unit(old unit #, new unit #, prefix)                }
      { "new unit" then becomes a unit on the same disc as "old unit",}
      { which must already exist.  This fails unless new unit is not  }
      { yet used, or if the prefix fails.  The prefix should not in-  }
      { clude a volume name or number.                                }
      { Example:                                                      }
      {         extra_HFS_unit(11, 12, '/PROGS');                     }

  end;

  { re-open the standard system files }
  openfiles;

end. {ctable}
@


56.3
log
@
pws2rcs automatic delta on Wed Jan 27 13:14:25 MST 1993
@
text
@d425 2
d1123 23
d1640 1
d1660 2
d1713 11
d1728 1
a1728 1
label   1;
d1739 14
a1752 2
		if (ioresult <> ord(inoerror)) or (dt <> 0) then
			{error on communication or not a disk type}
d1755 3
a1757 1
		if (SCSIRemovable) and (SCSIRemovableOption = AllAreHard) then
d1762 2
a1763 1
		call(ScsiDiscSizeProc.DiscSize, pSB, nbps, nspt, ntpc, nc);
d1794 1
a1794 1

a1802 1

d1836 1
d2060 7
d2068 1
a2068 1
	else tapes, printers, etc. not supported.
d2118 2
a2119 1
	  log_SCSI_MSUS;  {only disks are supported right now}
d2210 1
d2406 1
a2406 1
  { CS80 tapes }
d2417 9
@


56.2
log
@
pws2rcs automatic delta on Wed Jan 27 11:57:27 MST 1993
@
text
@d1 2657
@


56.1
log
@Automatic bump of revision number for PWS version 3.25
@
text
@a0 2657
					       (*

 (c) Copyright Hewlett-Packard Company 1983,
1984, 1985, 1987, 1989, 1990, 1991.
All rights are reserved.  Copying or other
reproduction of this program except for archival
purposes is prohibited without the prior
written consent of Hewlett-Packard Company.


	    RESTRICTED RIGHTS LEGEND

Use, duplication, or disclosure by the U.S. Government
is subject to restrictions as set forth in
subdivision (b)(3)(ii) of the Rights in Technical
Data and Computer Software clause at 52.227-7013.
Hewlett-Packard Company, 3000 Hanover Street,
Palo Alto CA 94304
						 *)


$page, sysprog$
$ALLOW_PACKED ON$ { JWS 4/10/85 }
$partial_eval on$

(********************************************************)
(*                                                      *)
(*  Note: You will need to use one of the following     *)
(*  compiler directives if the 'INTERFACE'              *)
(*  file is not in your current LIBRARY.                *)
(*  Choose the appropriate volume name  for             *)
(*  your configuration. If you are using                *)
(*  double-sided 3-1/2" media, the INTERFACE            *)
(*  file will be found on the ACCESS: volume.           *)
(*                                                      *)
(*  $search  'CONFIG:INTERFACE.'$                       *)
(*  $search  'ACCESS:INTERFACE.'$                       *)
(*                                                      *)
(********************************************************)

program {self-configuring} ctable;

module options;

  (********************************************)
  (* Choose the desired configuration options *)
  (* by editing the CONSTant declarations in  *)
  (* this module.                             *)
  (********************************************)

import
  sysglobals;

export

{INTERNAL ONLY BEGIN}
{ All internal-only code begins and ends as above and below.
{ MKCTBETA creates customer version from this internal source,
{ and it requires exactly the same spacing and capitalization
{ as in this example.  If there is an external version of
{ some code, it is introduced in an internal block like this
{EXTERNAL VERSION
{INTERNAL ONLY END}

{two possible versions of TABLE}
  const
    hfsversion  = 2;    { LIF primary DAM, HFS secondary }
    ucsdversion = 1;    { LIF primary DAM, UCSD secondary }

{change this assignment to get different versions}
  const
    thisversion = hfsversion;

{power-up system unit}
  const
    specified_system_unit =
      0;  {<>0 overrides auto-assignment}


{floppy/harddisc unit number slot tradeoff's}
  const
    floppy_unit_pairs =  {[1..10]}
      3;
    first_harddisc_lun = {do not edit!}
      7+(floppy_unit_pairs-1)*2;
    last_harddisc_lun =
      40;

$page$

{local printer type option}
  type
    local_printer_type = (HPIB, RS232, PARALLEL); {12/89 DEW - added PARALLEL}
  const
    local_printer_option = HPIB;


{local printer timeout}
  {
    maximum allowed delay between any two bytes:
      >0  specifies milliseconds (up to one hour)
      =0  specifies infinite timeout

    recommended values:
      -  HP2630 series  (HP-IB)       3000
      -  HP2670 series  (HP-IB)       3000
      -  HP9876         (HP-IB)       7000
      -  HP82905        (HP-IB)      12000
    Note: the HP82905 is currently NOT supported
      due to its improper response to interface
      clear (IFC), and its incompatible graphics
      dump sequence.

      -  HP LaserJet    (PARALLEL)   10000
  }
  const
    local_printer_timeout =
      $IF local_printer_option=HPIB$
	12000;  {milliseconds}
      $END$
      $IF local_printer_option=RS232$
	0;      {infinite}
      $END$
      $IF local_printer_option=PARALLEL$
	10000;  {milliseconds}
      $END$


{default dav's for devices not found by scanning}
  type
    dav_type = {device address vector}
      packed record
	sc, ba, du, dv: -128..127;
      end;
  const
    HP9885_default_dav =
      dav_type[sc: 12, ba: -1, du:  0, dv: -1];
    SRM_default_dav =
      dav_type[sc: 21, ba: {node} 0,
	       du: {unit} 8, dv: -1];
    BUBBLE_default_dav =
      dav_type[sc: 30, ba:  0, du:  0, dv:  0];
    local_HPIB_printer_default_dav =
      dav_type[sc:  7, ba:  1, du: -1, dv: -1];
    local_RS232_printer_default_dav =
      dav_type[sc:  9, ba:  0, du: -1, dv: -1];
    local_PARALLEL_printer_default_dav =
      dav_type[sc:  23, ba:  0, du: -1, dv: -1];

$page$

{local hard disc partitioning parameters}
  type
    pp_type =  {partitioning parameters}
      record
	mvs: integer;   {min vol size in bytes}
	mnv: shortint;  {max number of volumes}
      end;
  {   In general, MNV puts an upper bound on the
    number of logical volumes that a physical
    volume can be partitioned into.  Depending
    upon MNV's range, however, several types of
    behavior can occur.
      If MNV=0, then no logical volumes will ever
    be assigned for the device.
      If abs(MNV)=1, then exactly one logical
    volume will be assigned per physical volume
    of the device.  This corresponds to the
    2.X CTABLE's "single_volume" mode.
      If MNV>1, then partitioning will always be
    performed, subject to meeting the minimum
    volume size restrictions.  This corresponds
    to the 2.X CTABLE's "multi_volume" mode.
      If MNV<-1, then partitioning will be
    performed, but afterwards any logical volume
    that does not contain a valid directory will
    be coalesced with a previous adjacent logical
    volume if that one DOES contain a valid
    directory. As an extreme case, if only a
    single directory exists, and it is at the
    beginning of the physical volume, then all
    following logical volumes will be coalesced
    with the first, providing the same behavior
    as the 2.X CTABLE's "auto_volume" mode. With
    the less extreme cases, a wide variety of
    partitioning options are now possible without
    modification to CTABLE.                     }
  const
    min_size = {in bytes [1..maxint]}
      1000000;
    max_vols = {[-30..30]; <0 means autocoalesce}
      -30;
    HP913X_A_pp =
      pp_type[mvs: min_size, mnv: max_vols];
    HP913X_B_pp =
      pp_type[mvs: min_size, mnv: max_vols];
    HP913X_C_pp =
      pp_type[mvs: min_size, mnv: max_vols];
{INTERNAL ONLY BEGIN}
    HP7905_pp =  {historical value of mvs}
      pp_type[mvs:   983040, mnv: max_vols];
    HP7906_pp =  {historical value of mvs}
      pp_type[mvs:   983040, mnv: max_vols];
    HP7920_pp =
      pp_type[mvs: min_size, mnv: max_vols];
    HP7925_pp =
      pp_type[mvs: min_size, mnv: max_vols];
{INTERNAL ONLY END}
    CS80disc_pp =
      pp_type[mvs: min_size, mnv: max_vols];
    SCSIdisc_pp =                                {DEW 9/89 - added SCSI support}
      pp_type[mvs: min_size, mnv: max_vols];
$page$

{system unit auto-search declarations}
  const
    sysunit_list_length =
      7;
  type
    sysunit_list_type =
      array[1..sysunit_list_length] of unitnum;
  const
    sysunit_list =
      sysunit_list_type[
	  first_harddisc_lun, {first hard disc logical unit number}
	  45,   {srm, prefixed to user's sysvol}
	  4,    {floppy unit 1, primary DAM}
	  44,   {floppy unit 1, secondary DAM}
	  3,    {floppy unit 0, primary DAM}
	  43,   {floppy unit 0, secondary DAM}
	  42];  {bubble}


{HP-IB select code scanning declarations}
  const
    sc_list_length =
      3;
  type
    sc_list_type =
      array[1..sc_list_length] of shortint;
  const
    sc_list =
      sc_list_type[
	  7,    {internal HP-IB}
	  8,    {default sc for HP98624 HP-IB}
	  14];  {default sc for HP98625 HP-IB}

{SCSI select code scanning declarations}
  const
    SCSIsc_list_length =
      3;
  type
    SCSIsc_list_type =
      array[1..SCSIsc_list_length] of shortint;
  const
    SCSIsc_list =
      SCSIsc_list_type[
	  14,    {default sc for HP98265A (internal) and HP98658A (external)}
	  15,    {external SCSI sc when internal HP-IB/SCSI present at sc 14}
	  28];   {internal SCSI on 340/345}

{
  SCSI removable media may be an optical disk which has capacities of
  greater than 300Meg!  Therefore removable media can be configured to
  be:
	1:  A Hard disk if it has a size greater than 10M.
	2:  A Hard disk always.
	3:  A Floppy disk always.


  Things to be aware of when SCSI removable media is being treated like a
  hard disk:

    1: If the removable media is not on line at the time CTABLE is executed,
       the size of the disk is not available.  If the AllAreHard option is
       being used, then a unit entry will NOT be created for it.  If the
       AllOver10MAreHard option is used, then a unit entry for a floppy disk
       will be created for it.

    2: CTABLE will attempt the PREVENT MEDIUM REMOVAL command.  Through the
       SCSI programmer's interface, the ALLOW MEDIUM REMOVAL command may be
       sent.

    3: If the removable media goes off line for any reason, such as removing
       the media, PWS will discontinue communication with that device until
       CTABLE has been rerun.
}
   type
	SCSIRemovableOptionsType = (AllOver10MAreHard,
				    AllAreHard,
				    AllAreFloppy);
   const
	SCSIRemovableOption = AllOver10MAreHard;



implement {options}

end; {options}
$page, range off, ovflcheck off, partial_eval on$

module ctr; {ctable routines}

  (********************************************)
  (*                                          *)
  (*               Warning:                   *)
  (*   This module should not be modified!    *)
  (*                                          *)
  (********************************************)

import
  sysglobals, loader, options, ldr, fs, bootdammodule;

export

  const {mass storage letter specifiers}
    INTERNAL  = 'M';
    HP8290X   = 'N';
    HP9885    = 'F';
    HP9895    = 'H';
    HP913X_A  = 'U';
    HP913X_B  = 'V';
    HP913X_C  = 'W';
{INTERNAL ONLY BEGIN}
    HP7905    = 'Y';
    HP7906    = 'C';
    HP7920    = 'P';
    HP7925    = 'X';
{INTERNAL ONLY END}
    CS80      = 'Q';
    SRM       = 'G';
    PRINTER   = 'J';
    RAM       = 'R';
    BUBBLE    = 'B';
    EPROM     = 'E';
    SCSI      = 'S';      {DEW 09/89 - added SCSI support}
    NODEVICE  = #255;


  type
    flpy_flags_type = {flags governing floppy unit pair assignments}
      packed record
	assign_even_unit, assign_odd_unit: boolean;
      end;

  const
    assign_neither_flpy_unit =
      flpy_flags_type[assign_even_unit: false, assign_odd_unit: false];
    assign_both_flpy_units =
      flpy_flags_type[assign_even_unit: true, assign_odd_unit: true];

  type
    MSUS_type = {Mass Storage Unit Specifier}
      record
	flpy_flags: flpy_flags_type;
	letter: char;  {from the above mass storage letter specifiers}
	dav: dav_type;
      end;
$page$

    mp_type =  {medium parameters}
      record
	tpm: integer;  {tracks per medium}
	bpt: integer;  {bytes per track}
      end;

    ds_type =  {Directory access method Specifier for local mass storage}
      ( primary_dam,     {normally LIF }
	secondary_dam,   {HFS or UCSD, depending on choice in options}
	LIF_dam,         {LIF, regardless of primary/secondary choice}
	UCSD_dam,        {UCSD, regardless of primary/secondary choice}
	HFS_dam   );     {HFS, regardless of primary/secondary choice}

  var
    bootdev_MSUS: MSUS_type;
    bootdev_lun: unitnum;
    hfs_installed: boolean;

  procedure create_temp_unitable;
  procedure assign_and_clear_unit(lunit: unitnum);
  procedure assign_temp_unitable;
  function sysunit_ok(system_unit: unitnum): boolean;
  procedure zap_assigned_unit(lunit: unitnum);
  function on_same_medium(lun1, lun2: unitnum): boolean;
  procedure remove_extraneous_volumes(first_lun, last_lun: unitnum);
  function medium_parameters(letter: char): mp_type;
  function partitioning_parameters(letter: char): pp_type;
  function number_vols(mp: mp_type; pp: pp_type): shortint;
  function svol_bytes(letter: char): integer;
  function vol_bytes(current_vol, number_vols: shortint; mp: mp_type): integer;
  function vol_offset(current_vol, number_vols: shortint; mp: mp_type): integer;
  function block_boundaries(mp: mp_type): mp_type;
  function value(symbol: string255): integer;
  function MSUSs_match(MSUS1, MSUS2: MSUS_type): boolean;
  procedure extra_HFS_unit(oldun, newun: unitnum; prefix: string255);
  procedure install_HFS(un: unitnum; force: boolean);



  { table entry assignment procedures }

  procedure tea_memory_volume_dam(ds:ds_type);
  procedure tea_boot(un:unitnum);
  procedure tea_srm(un:unitnum;sc,ba,du:shortint);
  procedure tea_crt(un:unitnum);
  procedure tea_kbd(un:unitnum);
  procedure tea_local_printer(un:unitnum;sc,ba:shortint;uvid:vid;bto:integer);
  procedure tea_mini(un:unitnum;ds:ds_type;du:shortint);
  procedure tea_HP9885(un:unitnum;ds:ds_type;sc,du,block_os:shortint);
  procedure tea_HP9895(un:unitnum;ds:ds_type;sc,ba,du,block_os:shortint);
  procedure tea_HP8290X(un:unitnum;ds:ds_type;sc,ba,du:shortint);
  procedure tea_flpy(un:unitnum;lr:char;ds:ds_type;sc,ba,du:shortint);
{INTERNAL ONLY BEGIN}
  procedure tea_amigo_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;os:integer;lr:char;mb:integer);
{INTERNAL ONLY END}
  procedure tea_amigo_sv(un:unitnum;ds:ds_type;sc,ba,du:shortint;os:integer;lr:char;mb:integer);
  procedure tea_CS80_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;
					    os,id,mb,disksize:integer);
  procedure tea_CS80_sv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint);
  procedure tea_BUBBLE(un:unitnum;ds:ds_type;sc:shortint);
  procedure tea_EPROM(un:unitnum;ds:ds_type;sn:shortint);
  procedure tea_SCSI_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;
					    os,id,mb,disksize:integer); {DEW 09/89 - added SCSI support}
  procedure tea_SCSI_sv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint);    {DEW 09/89 - added SCSI support}
$page$

implement {ctr}

const  {abbreviation for tea procedure calls}
  T = true;
  F = false;

const  {actual driver entry point names}
  NO_DAM_name         = 'INITUNITS_NODAM';
  BOOT_DAM_name       = 'BOOTDAMMODULE_BOOTDAM';
  LIF_DAM_name        = 'LIFMODULE_LIFDAM';
  UCSD_DAM_name       = 'UCSDMODULE_UCSD_DAM';
  UNBLOCKED_DAM_name  = 'MISC_UNBLOCKEDDAM';
  SRM_DAM_name        = 'SRMDAMMODULE_SRMDAM';
  HFS_DAM_name        = 'HFS_DAM_MODULE_HFSDAM';

  NULL_TM_name        = 'INITUNITS_NOUNIT';
  BOOT_TM_name        = 'BOOTDAMMODULE_BOOTTM';
  CRT_TM_name         = 'SYSDEVS_CRTIO';
  KBD_TM_name         = 'SYSDEVS_KBDIO';
  MINI_TM_name        = 'MINI_MINIIO';
  SRM_TM_name         = 'SRMAMMODULE_SRMAM';
  PRINTER_TM_name     = 'PRTDVR_PRTIO';
  F9885_TM_name       = 'F9885DVR_F9885IO';
  AMIGO_TM_name       = 'AMIGODVR_AMIGOIO';
  CS80_TM_name        = 'CS80DVR_CS80IO';
  BUBBLE_TM_name      = 'BUBBLE_BUB_TM';
  EPROM_TM_name       = 'EPROMS_EPROM_TM';
  HFS_TM_name         = 'HFS_TM_MODULE_HFSTM';
  SCSIDSC_TM_name     = 'SCSIDISCMODULE_SCSIDISC';{09/89 DEW - added SCSI support}


var
  temp_unitable: unitableptr;
  temp_h_unitable: ^h_unitabletype;

procedure delay_timer(t:integer); external; {JWS 6/16/87}

procedure swap_h_units(u: unitnum);
  var
    t_unit: h_unittype;
  begin
    t_unit := h_unitable^.tbl[u];
    h_unitable^.tbl[u] := temp_h_unitable^.tbl[u];
    temp_h_unitable^.tbl[u] := t_unit;
  end;

procedure check(parameter, lower_bound, upper_bound: integer);
  begin
    if (parameter<lower_bound) or (parameter>upper_bound) then
      halt(-8) {value range error}
  end;

$page$

function value(symbol: string255): integer;
  var
    modp: moddescptr;
    ptr, valueptr: addrec;
    found: boolean;
  begin {value}
    value := 0;
    found := false;
    modp := sysdefs;
    while (modp<>nil) and not found do
      with modp^ do
	begin
	  ptr := defaddr;
	  while (ptr.a<defaddr.a+defsize) and not found do
	    begin
	      found := ptr.syp^=symbol;
	      ptr.a := ptr.a+strlen(ptr.syp^)+1;
	      ptr.a := ptr.a+ord(odd(ptr.a));
	      valueptr.a := ptr.a+2;
	      if found then
		value := valueptr.vep^.value;
	      ptr.a := ptr.a+ptr.gvp^.short;
	    end; {while}
	  modp := link;
	end; {with modp^}
  end; {value}


function MSUSs_match(MSUS1, MSUS2: MSUS_type): boolean;
  begin {MSUSs_match}
    MSUSs_match := (MSUS1.letter = MSUS2.letter) and
		   (MSUS1.dav.sc = MSUS2.dav.sc) and
		   (MSUS1.dav.ba = MSUS2.dav.ba) and
		   (MSUS1.dav.du = MSUS2.dav.du) and
		   (MSUS1.dav.dv = MSUS2.dav.dv);
  end; {MSUSs_match}

{
{ Make a new unit table entry at newun (must be free).
{ The medium is the same as oldun (must be HFS).
{ Prefix the new unit to the given directory name.
}
procedure extra_HFS_unit(oldun, newun: unitnum; prefix: string255);
  label
    999;
  var
    old_h_unit: h_unittype;
    old_unit: unitentry;
    i, un: integer;
    kvid: vid;
    dirname: fid;
  begin
    { new unit must be unused }
    if unitable^[newun].letter <> #0 then
      goto 999;

    { old unit must be HFS }
    if h_unitable = NIL then    {protect against ^nil. SFB}
     goto 999;

    if not h_unitable^.tbl[oldun].is_hfsunit then
      goto 999;

    { save unitable, h_unitable entries at new unit }
    old_unit := unitable^[newun];
    old_h_unit := h_unitable^.tbl[newun];

    { make newun and oldun look the same }
    unitable^[newun] := unitable^[oldun];
    h_unitable^.tbl[newun] := h_unitable^.tbl[oldun];

    { do the prefix }
    setstrlen(dirname, 0);
    strwrite(dirname, 1, i, '#', newun:1, ':', prefix);
    doprefix(dirname, kvid, un, true);

    { if it failed, reset the new unit }
    if ioresult <> ord(inoerror) then begin
      unitable^[newun] := old_unit;
      h_unitable^.tbl[newun] := old_h_unit;
    end;

  999:
  end;

{
{ Install HFS on this unit.
{ force -> install HFS always
{ not force -> install HFS if superblock is there
}
procedure install_HFS(un: unitnum; force: boolean);
  var
    dam_proc:
      packed record case integer of
	0: (dam: damtype);
	1: (value, slink: integer);
      end;

    tm_proc:
      packed record case integer of
	0: (tm: amtype);
	1: (value, slink: integer);
      end;
  begin
    if h_unitable <> nil then with h_unitable^ do begin
      call(init_unit_proc, un, force);
      { not force -> init_unit_proc sets is_hfsunit if recognized }
      if force or tbl[un].is_hfsunit then begin
	dam_proc.value := value(HFS_DAM_name);
	dam_proc.slink := 0;
	tm_proc.value := value(HFS_TM_name);
	tm_proc.slink := 0;
	with unitable^[un] do begin
	  dam := dam_proc.dam;
	  tm := tm_proc.tm;
	  uvid := '';
	end;
      end;
    end;
  end;


$page$

procedure tea {lowest-level Table Entry Assignment procedure}
    ( un:unitnum;                  {unit number}
      dam_name: string255;         {directory access method}
      tm_name: string255;          {transfer method (driver)}
      p_sc: shortint;              {select code}
      p_ba: shortint;              {bus address}
      p_du: shortint;              {disc unit}
      p_dv: shortint;              {disc volume}
      p_byteoffset: integer;       {physical starting byte of volume}
      p_devid: integer;            {device identifier (driver dependent)}
      p_uvid: vid;                 {volume id}
    { p_drvtemp: integer           {driver temp}
    { p_drvtemp2: shortint;        {second driver temp}
      p_letter: char;              {device specifier letter}
    { p_offline: boolean           {unit offline flag}
      p_uisinteractive: boolean;   {device echos input}
    { p_umediavalid: boolean;      {open files are valid}
    { p_uuppercase: boolean;       {volume name should be uppercased}
      p_uisfixed: boolean;         {medium not removable flag}
    { p_ureportchange: boolean;    {driver directive to report/ignore medium changes}
    { p_pad: 0..1                  {(not used)}
      p_uisblkd: boolean;          {blocked volume flag}
      p_umaxbytes: integer;        {volume size in bytes (unit)}
      p_disksize: integer  );      {volume size in bytes (disk)}

  var
    dam_proc:
      packed record case integer of
	0: (dam: damtype);
	1: (value, slink: integer);
      end;

    tm_proc:
      packed record case integer of
	0: (tm: amtype);
	1: (value, slink: integer);
      end;

    dam_ok: boolean;

    old_unit : unitentry;       {for "missing LIFDAM" bug fix. SFB}
		{This bug showed up when LIFDAM was not in INITLIB, but
		 HFSDAM was. If a superblock is on the disc, HFSDAM should
		 connect, but didn't, mainly because of the
		 'if (dam_proc.value <> 0)' test farther on.
		 We no longer do that test, but have to ensure the unit
		 doesn't get set up if the DAM is not available. SFB}

  procedure swap_temp_and_real_unit;
  var
     tmpunit: unitentry;
  begin
     tmpunit := unitable^[un];
     unitable^[un] := temp_unitable^[un];
     temp_unitable^[un] := tmpunit;
  end;

  begin {tea}
    if temp_unitable=nil then halt(-3); {unassigned pointer}

    { HFS only at beginning of disk (RAM units never tea'd) }
    if (dam_name = HFS_DAM_name) and (p_byteoffset <> 0) then
      dam_name := '';  {was LIF_DAM_name. Need value=0. SFB}

    dam_proc.value := value(dam_name);
    dam_proc.slink := 0;

    tm_proc.value := value(tm_name);
    tm_proc.slink := 0;

    old_unit := temp_unitable^[un]; {to restore later, if DAM not found. SFB}

    if
   { (dam_proc.value<>0) and           {removed. SFB}
     (tm_proc.value<>0) then  {assign the entry}
      begin

	with temp_unitable^[un] do
	  begin
	    dam             := dam_proc.dam;
	    tm              := tm_proc.tm;
	    sc              := p_sc;
	    ba              := p_ba;
	    du              := p_du;
	    dv              := p_dv;
	    byteoffset      := p_byteoffset;
	    devid           := p_devid;
	    uvid            := p_uvid;
	    dvrtemp         := 0;                 {always initially zero!}
	    dvrtemp2        := -1;                {always initially -1!}
	    letter          := p_letter;
	    offline         := false;             {always initially online!}
	    uisinteractive  := p_uisinteractive;
	    umediavalid     := false;             {never valid to start with}
	    uuppercase      := not p_uisblkd;     {assume case is significant}
	    uisfixed        := p_uisfixed;
	    ureportchange   := true;              {do report media changes}
	    pad             := 0;                 {not used}
	    uisblkd         := p_uisblkd;
	    if uisblkd then
	      umaxbytes     := p_umaxbytes;

	    if ( (tm_name = SCSIDSC_TM_name) and
		 ( (SCSIRemovableOption = AllAreHard) or
		   ( (SCSIRemovableOption = AllOver10MAreHard) and
		     (p_disksize >= hex('A00000'))
		   )
		 )
	       ) then
			pad := 1;
	  end; {with}


	if hfsbflg then
	  dam_ok := value(HFS_DAM_name)<>0      {SFB}
	else
	  if dam_proc.value <> 0 then           {SFB}
	    dam_ok := (dam_name=LIF_DAM_name) or (dam_name=SRM_DAM_name);

	with bootdev_MSUS, dav do {see if this entry points to it}
	  if (p_letter=letter) and  {wish we could use MSUSs_match function}
	     (p_sc=sc) and (p_ba=ba) and (p_du=du) and (p_dv=dv) and
	     dam_ok and
	     (p_byteoffset=0) then  {remember this unit number!}
	    bootdev_lun := un;

	if h_unitable <> nil then with h_unitable^ do begin
	  { temporarily swap temp and real unit entries }
	  swap_h_units(un);
	  swap_temp_and_real_unit;

	  if dam_name = HFS_DAM_name then
	    { force this unit to be HFS }
	    install_HFS(un, true)
	  else
	  if (p_byteoffset = 0)
	{ and (dam_name = LIF_DAM_name) {removed, as it blocks WS1.0, etc. SFB}
	  and (un >= first_harddisc_lun)
	  and (un <= last_harddisc_lun) then
	    { install HFS if disk has a superblock }
	    install_HFS(un, false);

	  if tbl[un].is_hfsunit then begin
	    { take up whole disk }
	    if p_disksize <> 0 then
	      unitable^[un].umaxbytes := p_disksize;
	    { prevent further units on this disk }
	    hfs_installed := true;
	  end;
	  swap_h_units(un);
	  swap_temp_and_real_unit;
	end;

      end; {if}

    {see if we found a dam for the unit. SFB}
    if temp_h_unitable <> NIL then
     with temp_h_unitable^ do   {was DAM found or HFS installed ?}
      begin
       if (not tbl[un].is_hfsunit) and (dam_proc.value=0) then
	temp_unitable^[un]:=old_unit  {if not, uninstall the entry. SFB}
      end
    else        {no possibility HFSDAM was installed}
     if dam_proc.value=0 then
      temp_unitable^[un]:=old_unit;   {if no dam, uninstall the entry. SFB}

  end; {tea}


function dam(ds: ds_type): string255;
  begin
    case ds of
$if thisversion = hfsversion$
      primary_dam:
	dam := LIF_DAM_name;
      secondary_dam:
	dam := HFS_DAM_name;
$end$
$if thisversion = ucsdversion$
      primary_dam:
	dam := LIF_DAM_name;
      secondary_dam:
	dam := UCSD_DAM_name;
$end$
      HFS_dam:
	dam := HFS_DAM_name;
      LIF_dam:
	dam := LIF_DAM_name;
      UCSD_dam:
	dam := UCSD_DAM_name;
    end; {case}
  end;
$page$

function medium_parameters(letter: char): mp_type;
  const {LOGICAL sizes unless otherwise noted}
    INTERNAL_mp = mp_type[tpm: 2* 33, bpt: 16*256];
    HP8290X_mp  = mp_type[tpm: 2* 33, bpt: 16*256];
    HP9885_mp   = mp_type[tpm: 1* 77, bpt: 30*256];  {physical size}
    HP9895_mp   = mp_type[tpm: 2* 77, bpt: 30*256];  {physical size}
    HP913X_A_mp = mp_type[tpm: 4*152, bpt: 31*256];
    HP913X_B_mp = mp_type[tpm: 4*305, bpt: 31*256];
    HP913X_C_mp = mp_type[tpm: 6*305, bpt: 31*256];
{INTERNAL ONLY BEGIN}
    HP7905_mp   = mp_type[tpm: 2*400, bpt: 48*256];  {fixed is half this size}
    HP7906_mp   = mp_type[tpm: 2*400, bpt: 48*256];  {fixed & remov same size}
    HP7920_mp   = mp_type[tpm: 5*800, bpt: 48*256];
    HP7925_mp   = mp_type[tpm: 9*800, bpt: 64*256];
{INTERNAL ONLY END}
    BUBBLE_mp   = mp_type[tpm: 1*512, bpt:  1*256];  {1 megabit unit}
   {BUBBLE_mp   = mp_type[tpm: 4*512, bpt:  1*256];} {4 megabit unit}
    null_mp     = mp_type[tpm:     0, bpt:      0];
  begin
    case letter of
      INTERNAL:  medium_parameters := INTERNAL_mp;
      HP8290X:   medium_parameters := HP8290X_mp;
      HP9885:    medium_parameters := HP9885_mp;
      HP9895:    medium_parameters := HP9895_mp;
      HP913X_A:  medium_parameters := HP913X_A_mp;
      HP913X_B:  medium_parameters := HP913X_B_mp;
      HP913X_C:  medium_parameters := HP913X_C_mp;
{INTERNAL ONLY BEGIN}
      HP7905:    medium_parameters := HP7905_mp;
      HP7906:    medium_parameters := HP7906_mp;
      HP7920:    medium_parameters := HP7920_mp;
      HP7925:    medium_parameters := HP7925_mp;
{INTERNAL ONLY END}
      BUBBLE:    medium_parameters := BUBBLE_mp;
      otherwise  medium_parameters := null_mp;
    end; {case}
  end;


function partitioning_parameters(letter: char): pp_type;
  const
    null_pp = pp_type[mvs: 0, mnv: 0];
  begin
    case letter of
      HP913X_A:  partitioning_parameters := HP913X_A_pp;
      HP913X_B:  partitioning_parameters := HP913X_B_pp;
      HP913X_C:  partitioning_parameters := HP913X_C_pp;
{INTERNAL ONLY BEGIN}
      HP7905:    partitioning_parameters := HP7905_pp;
      HP7906:    partitioning_parameters := HP7906_pp;
      HP7920:    partitioning_parameters := HP7920_pp;
      HP7925:    partitioning_parameters := HP7925_pp;
{INTERNAL ONLY END}
      CS80:      partitioning_parameters := CS80disc_pp;
      SCSI:      partitioning_parameters := SCSIdisc_pp;        {DEW 09/89 - added SCSI support}
      otherwise  partitioning_parameters := null_pp;
    end; {case}
  end;
$page$

function number_vols(mp: mp_type; pp: pp_type): shortint;
  var
    nvols: shortint;
  begin
    if pp.mnv<0 then  {negative implies autovolume feature; use absolute value}
      pp.mnv := -pp.mnv;
    if pp.mvs<=0 then pp.mvs := 1;  {guard against div's by 0}
    if mp.bpt<=0 then mp.bpt := 1;  {guard against div's by 0}
    nvols := mp.tpm div ((pp.mvs+mp.bpt-1) div mp.bpt);
    if (nvols=0) and (mp.tpm>0) then
      nvols := 1;  {physical vol smaller than the specified minimum vol size}
    if nvols>pp.mnv then  {cut back, even to zero if specified}
      nvols := pp.mnv;
    number_vols := nvols;
  end;


function svol_bytes(letter: char): integer;
  var
    mp: mp_type;
  begin
    mp := medium_parameters(letter);
    svol_bytes := mp.bpt*mp.tpm;  {single volume bytes}
  end;


function vol_bytes(current_vol, number_vols: shortint; mp: mp_type): integer;
  var
    tracks: integer;
  begin
    tracks := mp.tpm div number_vols;           {each vol gets this much}
    if current_vol=number_vols-1 then
      tracks := tracks+mp.tpm mod number_vols;  {last vol gets any extra}
    vol_bytes := tracks*mp.bpt;
  end;


function vol_offset(current_vol, number_vols: shortint; mp: mp_type): integer;
  begin
    vol_offset := (mp.tpm div number_vols)*current_vol*mp.bpt;
  end;


function block_boundaries(mp: mp_type): mp_type;
  begin
    block_boundaries.tpm := mp.tpm*mp.bpt div 512;
    block_boundaries.bpt := 512;
  end;
$page$

{ standard driver-oriented table entry assignment procedures }


procedure tea_nounit(un:unitnum);
  begin
    tea(un,NO_DAM_name,NULL_TM_name,0,0,0,0,0,0,'',#0,F,F,F,0,0);
  end;


procedure tea_memory_volume_dam(ds:ds_type);
  begin
    tea(0,dam(ds),NULL_TM_name,0,0,0,0,0,0,'',RAM,F,T,T,0,0);
  end;


procedure tea_crt(un:unitnum);
  begin
    tea(un,UNBLOCKED_DAM_name,CRT_TM_name,0,0,0,0,0,0,'CONSOLE',#0,T,T,F,0,0);
  end;


procedure tea_kbd(un:unitnum);
  begin
    tea(un,UNBLOCKED_DAM_name,KBD_TM_name,0,0,0,0,0,0,'SYSTERM',#0,F,T,F,0,0);
  end;


procedure tea_mini(un:unitnum;ds:ds_type;du:shortint);
  begin
    check(du, 0, 1);
    tea(un,dam(ds),MINI_TM_name,0,0,du,0,0,0,'',INTERNAL,
			      F,F,T,svol_bytes(INTERNAL),0);
  end;


procedure tea_boot(un: unitnum);
  begin
    tea(un,BOOT_DAM_name,BOOT_TM_name,0,0,0,0,0,0,'',#0,F,F,T,maxint,0);
  end;


procedure tea_srm(un:unitnum;sc,{node}ba,{unit}du:shortint);
  begin
    check(sc, 7, 31);
    check(ba, 0, 127);
    if du<>0 then check(du, 7, 26);
    tea(un,SRM_DAM_name,SRM_TM_name,sc,ba,du,0,0,0,'',SRM,F,T,T,maxint,0);
  end;


procedure tea_local_printer(un:unitnum;sc,ba:shortint;uvid:vid;bto:integer);
  begin
    check(sc, 7, 31);
    check(ba, 0, 30);
    check(bto, 0, 60*60*1000);  {one hour should be enough!}
    tea(un,UNBLOCKED_DAM_name,PRINTER_TM_name,sc,ba,0,0,0,bto,uvid,#0,
							    F,T,F,0,0);
  end;
$page$

procedure tea_HP9885(un:unitnum;ds:ds_type;sc,du,block_os:shortint);
  var
    os: integer;
  begin
    check(sc, 8, 31);
    check(du, 0, 3);
    os := block_os*512;
    check(os, 0, svol_bytes(HP9885)-1);
    tea(un,dam(ds),F9885_TM_name,sc,0,du,0,os,0,'',HP9885,
			    F,F,T,svol_bytes(HP9885)-os,0);
  end;


procedure tea_HP9895(un:unitnum;ds:ds_type;sc,ba,du,block_os:shortint);
  var
    os: integer;
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 3);
    os := block_os*512;
    check(os, 0, svol_bytes(HP9895)-1);
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,0,os,0,'',HP9895,
			       F,F,T,svol_bytes(HP9895)-os,0);
  end;


procedure tea_HP8290X(un:unitnum;ds:ds_type;sc,ba,du:shortint);
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 3);
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,0,0,0,'',HP8290X,
				  F,F,T,svol_bytes(HP8290X),0);
  end;


procedure tea_amigo_sv(un:unitnum;ds:ds_type;sc,ba,du:shortint;os:integer;lr:char;mb:integer);
  var
    medium_size: integer;
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 7);
{INTERNAL ONLY BEGIN}
    if not (lr in [HP913X_A, HP913X_B, HP913X_C, HP7920, HP7925]) then
{EXTERNAL VERSION
    if not (lr in [HP913X_A, HP913X_B, HP913X_C]) then
{INTERNAL ONLY END}
      halt(-8); {value range error}
    medium_size := svol_bytes(lr);
    check(os, 0, medium_size-1);
    if os mod 256<>0 then halt(-8) {value range error};
    check(mb, 1, medium_size-os);
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,0,os,0,'',lr,F,T,T,mb,medium_size);
  end;
$page$

{INTERNAL ONLY BEGIN}
procedure tea_amigo_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;os:integer;lr:char;mb:integer);
  var
    medium_size: integer;
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 7);
    check(dv, 0, 1);
    if not (lr in [HP7905, HP7906]) then halt(-8);  {value range error}
    medium_size := svol_bytes(lr);
    if (lr=HP7905) and (dv<>0) then
      medium_size := medium_size div 2;  {7905 fixed is half as big!}
    check(os, 0, medium_size-1);
    if os mod 256<>0 then halt(-8) {value range error};
    check(mb, 1, medium_size-os);
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,dv,os,0,'',lr,F,T,T,mb,medium_size);
  end;
{INTERNAL ONLY END}
$page$

procedure tea_CS80_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;os,id,
						   mb,disksize:integer);
  {
    CS80 multiple (logical) volume assignment procedure:
    1) devid must match the actual HP product number as found in describe
    2) offset and umaxbytes are fixed
    3) the uisfixed field is assigned by the driver in the clearunit procedure
  }
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 14);
    check(dv, 0, 7);
    tea(un,dam(ds),CS80_TM_name,sc,ba,du,dv,os,id,'',CS80,F,F,T,mb,disksize);
  end;


procedure tea_CS80_sv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint);
  {
    CS80 single (logical) volume assignment procedure:
    1) byteoffset always assumed to be zero
    2) umaxbytes is dependent upon the media loaded, thus it is set by the
       driver at clearunit time and whenever it detects a media change.
       BOTTOM LINE: the medium CANNOT be partitioned into multiple volumes!
    3) the uisfixed field is assigned by the driver in the clearunit procedure
    4) device can either be a disc (presumably a floppy) or a tape
  }
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 14);
    check(dv, 0, 7);
    tea(un,dam(ds),CS80_TM_name,sc,ba,du,dv,0,-1,'',CS80,F,F,T,0,0);
  end;


procedure tea_SCSI_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;os,id,
						   mb,disksize:integer);
  {
    09/89 DEW - added SCSI support
    SCSI multiple (logical) volume assignment procedure:
    1) devid must match the actual HP product number as found in describe
    2) offset and umaxbytes are fixed
    3) the uisfixed field is assigned by the driver in the clearunit procedure
  }
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 255);
    check(dv, 0, 0);   {SCSI Secondary Units not supported}
    tea(un,dam(ds),SCSIDSC_TM_name,sc,ba,du,dv,os,id,'',SCSI,F,F,T,mb,disksize);
  end;


procedure tea_SCSI_sv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint);
  {
    09/89 DEW - added SCSI support
    SCSI single (logical) volume assignment procedure:
    1) byteoffset always assumed to be zero
    2) umaxbytes is dependent upon the media loaded, thus it is set by the
       driver at clearunit time and whenever it detects a media change.
       BOTTOM LINE: the medium CANNOT be partitioned into multiple volumes!
    3) the uisfixed field is assigned by the driver in the clearunit procedure
    4) device can either be a disc (presumably a floppy) or a tape
  }
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 255);
    check(dv, 0, 0);   {SCSI Secondary Units not supported}
    tea(un,dam(ds),SCSIDSC_TM_name,sc,ba,du,dv,0,-1,'',SCSI,F,F,T,0,0);
  end;


procedure tea_flpy(un:unitnum;lr:char;ds:ds_type;sc,ba,du:shortint);
  begin
    case lr of
      INTERNAL: tea_mini(un,ds,du);
      HP8290X:  tea_HP8290X(un,ds,sc,ba,du);
      CS80:     tea_CS80_sv(un,ds,sc,ba,du,0);
      SCSI:     tea_SCSI_sv(un,ds,sc,ba,du,0);  {DEW 09/89 - added SCSI support}
      HP9885:   tea_HP9885(un,ds,sc,du,0);
      HP9895:   tea_HP9895(un,ds,sc,ba,du,0);
      otherwise halt(-8) {value range error}
    end;  {case}
  end;

$page$

procedure tea_BUBBLE(un:unitnum;ds:ds_type;sc:shortint);
  begin
    { NOTE THAT UMAXBYTES IS ASSIGNED AT CLEARUNIT TIME }
    check(sc,7,31);
    tea(un,dam(ds),BUBBLE_TM_name,sc,0,0,0,0,0,'',BUBBLE,F,T,T,0,0);
  end;

procedure tea_EPROM(un:unitnum;ds:ds_type;sn:shortint);
  begin
    { NOTE THAT UMAXBYTES IS ASSIGNED AT CLEARUNIT TIME }
    check(sn,0,MAXUNIT);
    tea(un,dam(ds),EPROM_TM_name,0,0,0,sn,0,0,'',EPROM,F,T,T,0,0);
  end;

$page$

procedure create_temp_unitable;
  var
    lunit: unitnum;
  begin
    new(temp_unitable);
    tea_nounit(0);  {assign one dummy entry}
    for lunit := 1 to maxunit do  {copy others; avoid symbol table search each time!}
      temp_unitable^[lunit] := temp_unitable^[0];
    if h_unitable <> nil then begin
      new(temp_h_unitable);
      temp_h_unitable^ := h_unitable^;
      call(h_unitable^.init_cache_proc);
      for lunit := 0 to maxunit do
	swap_h_units(lunit);
      { now h_unitable is as before, temp_h_unitable is initialized }
    end;
  end;


procedure assign_and_clear_unit(lunit: unitnum);
  var
    f: fib;
  begin
    if temp_unitable=nil then halt(-3); {unassigned pointer}
    with unitable^[lunit], f do
      if (letter<>RAM) or (lunit=0) then
	begin
	  unitable^[lunit] := temp_unitable^[lunit];
	  funit := lunit;
	  delay_timer(1000); { Fix for SRM coax configuration }
	  if h_unitable <> nil then
	    h_unitable^.tbl[lunit] := temp_h_unitable^.tbl[lunit];
	  call(tm, addr(f), clearunit, lunit, 0, 0);
	  offline := uisblkd and (ioresult<>0);
	end
	else
	  { try to convert old RAM volumes to HFS }
	  install_HFS(lunit, false);
  end;

{----------------------------------------------------------------------}
{
{ set the base_unum fields in h_unitable
{ base_unum is the unit number of the LOWEST unit on this disk
{ e.g., if #11 and #12 share a disk, base_unum for both is 11.
}
procedure set_base_unums;
var
    i,j: unitnum;
begin
    if h_unitable <> nil then with h_unitable^ do
	for i := 1 to maxunit do
	    for j := i+1 to maxunit do
		{ HFS? }
		if tbl[j].is_hfsunit
		{ higher number not yet assigned? }
		and (tbl[j].base_unum = j)
		{ share disk? }
		and on_same_medium(i, j) then
		    tbl[j].base_unum := i;
end;

procedure assign_temp_unitable;
  var
    lunit: unitnum;
    i: integer;
  begin
    if temp_unitable=nil then halt(-3);  {unassigned pointer}
    lockfiles;  {close all standard system files}
    for lunit := 0 to maxunit do
      assign_and_clear_unit(lunit);
    set_base_unums;
    { configure HFS cache }
    if h_unitable <> nil then begin
      call(h_unitable^.config_cache_proc);
    end;

  end;


function sysunit_ok(system_unit: unitnum): boolean;
  begin
    sysunit := system_unit;
    initsysunit;
    with unitable^[system_unit] do
      sysunit_ok := uisblkd and not offline and (uvid<>'');
  end;


procedure zap_assigned_unit(lunit: unitnum);
  begin
    tea_nounit(lunit);  {zap the temp unitable entry}
    unitable^[lunit] := temp_unitable^[lunit];  {now zap the real one!}
  end;
$page$

function on_same_medium(lun1, lun2: unitnum): boolean;
  var
    uep: ^unitentry;
  begin {on_same_medium}
    uep := addr(unitable^[lun2]);
    with unitable^[lun1] do
      on_same_medium := (sc=uep^.sc) and (ba=uep^.ba) and
			(du=uep^.du) and (dv=uep^.dv) and
			(letter=uep^.letter) and (letter<>'R');
  end; {on_same_medium}


procedure remove_extraneous_volumes(first_lun, last_lun: unitnum);
  var
    first_lun_ok: boolean;
    lun: unitnum;
  begin {remove_extraneous_volumes}
    first_lun_ok := false;
    while first_lun<last_lun do
      if first_lun_ok then
	begin
	  lun := first_lun+1;
	  with unitable^[first_lun] do
	    while (lun<=last_lun) and not sysunit_ok(lun) do
	      begin
		if unitable^[lun].byteoffset = byteoffset+umaxbytes then
		  begin
		    umaxbytes := umaxbytes+unitable^[lun].umaxbytes;
		    zap_assigned_unit(lun);
		  end;
		lun := lun+1;
	      end;  {while}
	  first_lun := lun;
	end {then}
      else if sysunit_ok(first_lun) then
	first_lun_ok := true
      else
	first_lun := first_lun+1;
  end; {remove_extraneous_volumes}

end; {ctr}
$page$

module BRstuff;  {BOOTROM stuff}

  (********************************************)
  (*                                          *)
  (*               Warning:                   *)
  (*   This module should not be modified!    *)
  (*                                          *)
  (********************************************)

import
  sysglobals, options, ctr;

export
  const
    INTERNAL_MSUS = MSUS_type
      [ flpy_flags: assign_neither_flpy_unit, letter: INTERNAL,
	dav: dav_type[sc: -1, ba: -1, du:  0, dv: -1] ];

  function internal_mini_present: boolean;
  procedure get_bootdevice_MSUS(var MSUS: MSUS_type);

implement {BRstuff}

type
  signed4     = -8..7;
  signed8     = -128..127;

  fmt_type =  {format field in the msus byte}
    (f0,f1,f2,f3,f4,f5,f6,f7);

  dev_type =  {device field in the msus byte}
    ( d0, d1, d2, d3, d4, d5, d6, d7, d8, d9,d10,d11,d12,d13,d14,d15,
     d16,d17,d18,d19,d20,d21,d22,d23,d24,d25,d26,d27,d28,d29,d30,d31);

  BR_msus_type = {BOOTROM's mass storage unit specifier}
    packed record case boolean of
      false:  {8-bit unit number}
	( fmt: fmt_type;  {directory format}
	  dev: dev_type;  {device}
	  un: signed8;    {8-bit unit number}
	  sc: signed8;    {select code}
	  ba: signed8     {bus address}  );
      true:  {4-bit volume / 4-bit unit number for CS80 & 7905/06 discs}
	( pad: signed8;   {format/device byte}
	  vn4: signed4;   {4-bit volume number}
	  un4: signed4;   {4-bit unit number}  );
    end; {BR_msus_type}

var
  ROM_ID[16382]:  {BOOTROM identification word}
    shortint;

  ndrives[-296]:  {Maximum Unit for Internal Mini-Floppy}
    packed record  b: signed8;  end;

  default_msus[-292]:  {boot device's msus}
    BR_msus_type;
$page$

function internal_mini_present: boolean;
  begin
    if ROM_ID<0
      then internal_mini_present := true            {1.0 BOOTROM on 9826}
      else internal_mini_present := ndrives.b<>-1;  {2.0 or greater BOOTROM}
  end;


procedure get_bootdevice_MSUS(var MSUS: MSUS_type);
  type
    letter_table_type = array[dev_type] of char;
  const
    letter_table =  {BOOTROM dev to Pascal letter conversion table}
      letter_table_type
	[ INTERNAL, NODEVICE, NODEVICE, NODEVICE, HP9895,   HP8290X,  HP9885,   HP913X_A,
{INTERNAL ONLY BEGIN}
	  HP913X_B, HP913X_C, HP7905,   HP7906,   HP7920,   HP7925,   SCSI,     NODEVICE, {DEW - added SCSI}
{EXTERNAL VERSION
	  HP913X_B, HP913X_C, NODEVICE, NODEVICE, NODEVICE, NODEVICE, SCSI,     NODEVICE, {DEW - added SCSI}
{INTERNAL ONLY END}
	  CS80,     CS80,     NODEVICE, NODEVICE, NODEVICE, NODEVICE, BUBBLE  , NODEVICE,
	  NODEVICE, NODEVICE, NODEVICE, NODEVICE, NODEVICE, NODEVICE, NODEVICE, NODEVICE  ];
  begin
    if ROM_ID<0 then  {1.0 Boot ROM on 9826; internal minifloppy only}
      MSUS := INTERNAL_MSUS
    else  {2.0 or greater Boot ROM}
      with default_msus do
	begin
	  if fmt=f7 then  {non sector-oriented device}
	    if (dev=d1) OR (dev=d2)    {added dev=d2 to allow LANSRM. DEW/RDQ/SFB - 5/5/89}
	      then MSUS.letter := SRM
	      else MSUS.letter := NODEVICE
	  else  {sector-oriented device}
	    MSUS.letter := letter_table[dev];
	  MSUS.dav.sc := sc;
	  MSUS.dav.ba := ba;
{INTERNAL ONLY BEGIN}
	  if MSUS.letter in [HP7905, HP7906, CS80, SCSI] then   {DEW 09/89 - added SCSI support}
{EXTERNAL VERSION
	  if MSUS.letter in [CS80, SCSI] then                   {DEW 09/89 - added SCSI support}
{INTERNAL ONLY END}
	    begin
	      MSUS.dav.du := un4;
	      MSUS.dav.dv := vn4;
	    end  {then}
	  else
	    begin
	      MSUS.dav.du := un;
	      MSUS.dav.dv := 0;
	    end;  {else}
	end; {with}
  end;

end; {BRstuff}
$page$

module scanstuff;

  (********************************************)
  (*                                          *)
  (*               Warning:                   *)
  (*   This module should not be modified!    *)
  (*                                          *)
  (********************************************)

import
  sysglobals, options, ctr;

export

  procedure init_scanstuff;
  function scanneddevice_letter(scan_dav: dav_type): char;
  procedure get_CS80_parms(CS80dav: dav_type;
			   var CS80dt: byte; var CS80id: integer;
			   var CS80hardvols: shortint; var CS80mp: mp_type);

implement {scanstuff}


type
  uep_type = ^unitentry;

  uep_proc_type = procedure(uep: uep_type);
  HPIBget_amigo_ident_type = procedure(uep: uep_type; var ident: shortint);
  get_letter_type = procedure(uep: uep_type; ident: shortint; var letter: char);
  get_CS80_parms_type = procedure(var CS80dt: byte;
				  var CS80id: integer;
				  var CS80hardvols: shortint;
				  var CS80mp: mp_type);

  proc_type =
    packed record case integer of
      0: (value, slink: integer);
      1: (up: uep_proc_type);
      2: (gai: HPIBget_amigo_ident_type);
      3: (gl: get_letter_type);
      4: (gcp: get_CS80_parms_type);
    end;


var
  allocate_bkgnd_info_proc: proc_type;
  deallocate_bkgnd_info_proc: proc_type;
  abort_bkgnd_process_proc: proc_type;
  HPIBcheck_sc_proc: proc_type;
  HPIBget_amigo_ident_proc: proc_type;

  get_amigo_letter_proc: proc_type;
  get_CS80_letter_proc: proc_type;
  get_CS80_parms_proc: proc_type;

  bkgnd_and_dischpib_present: boolean;
$page$

function scanneddevice_letter(scan_dav: dav_type): char;

  type
    amigo_class_type = {upper three bits of the first ident byte}
      (storage, display, data_communication, processor,
       stimulus, mesasurement, unassigned6, unassigned7);

  var
    ue: unitentry;
    ident:
      packed record case integer of
	0: (word: shortint);
	1: (upper_byte, lower_byte: byte);
	2: (amigo_class: amigo_class_type);
      end;

  procedure set_scanneddevice_letter(get_letter_proc: proc_type);
    var
      device_letter: char;
    begin {set_scanneddevice_letter}
      if get_letter_proc.value<>0 then
	begin
	  call(get_letter_proc.gl, addr(ue), ident.word, device_letter);
	  scanneddevice_letter := device_letter;
	end; {if}
    end; {set_scanneddevice_letter}

  begin {scanneddevice_letter}
    scanneddevice_letter := NODEVICE;  {until proven otherwise}
    if bkgnd_and_dischpib_present then
      try
	ue.sc := scan_dav.sc;
	ue.ba := scan_dav.ba;
	ue.du := scan_dav.du;
	ue.dv := scan_dav.dv;
	call(allocate_bkgnd_info_proc.up, addr(ue));
	call(HPIBcheck_sc_proc.up, addr(ue));
	call(HPIBget_amigo_ident_proc.gai, addr(ue), ident.word);
	if ident.amigo_class=storage then
	    if ident.upper_byte=2
	      then set_scanneddevice_letter(get_CS80_letter_proc)
	      else set_scanneddevice_letter(get_amigo_letter_proc)
	else if ident.amigo_class=display then
	    scanneddevice_letter := PRINTER;
	call(deallocate_bkgnd_info_proc.up, addr(ue));
      recover
	call(abort_bkgnd_process_proc.up, addr(ue));
  end; {scanneddevice_letter}
$page$

procedure get_CS80_parms(CS80dav: dav_type;
			 var CS80dt: byte; var CS80id: integer;
			 var CS80hardvols: shortint; var CS80mp: mp_type);
  begin {get_CS80_parms}
    if (scanneddevice_letter(CS80dav)=CS80) and (get_CS80_parms_proc.value<>0) then
      call(get_CS80_parms_proc.gcp, CS80dt, CS80id, CS80hardvols, CS80mp)
    else
      begin
	CS80dt := 255;
	CS80id := 0;
	CS80hardvols := 0;
	CS80mp := medium_parameters(NODEVICE);
      end; {else}
  end; {get_CS80_parms}


procedure init_scanstuff;
  {
    NOTE: all procedure variables are GLOBAL, so their static links are
	  guaranteed to have been cleared @@ load time
  }
  begin {init_scanstuff}
    allocate_bkgnd_info_proc.value   := value('BKGND_ALLOCATE_BKGND_INFO');
    deallocate_bkgnd_info_proc.value := value('BKGND_DEALLOCATE_BKGND_INFO');
    abort_bkgnd_process_proc.value   := value('BKGND_ABORT_BKGND_PROCESS');
    HPIBcheck_sc_proc.value          := value('DISCHPIB_HPIBCHECK_SC');
    HPIBget_amigo_ident_proc.value   := value('DISCHPIB_HPIBGET_AMIGO_IDENT');

    get_amigo_letter_proc.value      := value('AMIGODVR_GET_LETTER');
    get_CS80_letter_proc.value       := value('CS80DVR_GET_LETTER');
    get_CS80_parms_proc.value        := value('CS80DVR_GET_PARMS');

    bkgnd_and_dischpib_present := (allocate_bkgnd_info_proc.value<>0) and
				  (deallocate_bkgnd_info_proc.value<>0) and
				  (abort_bkgnd_process_proc.value<>0) and
				  (HPIBcheck_sc_proc.value<>0) and
				  (HPIBget_amigo_ident_proc.value<>0);
  end; {init_scanstuff}


end; {scanstuff}
$page$

module SCSIscanstuff;           {DEW 09/89 - added SCSI support}

  (********************************************)
  (*                                          *)
  (*               Warning:                   *)
  (*   This module should not be modified!    *)
  (*                                          *)
  (********************************************)


import sysglobals, asm, options, ctr;

export
	procedure init_SCSIscanstuff;
	function SCSIscanneddevice_letter(scan_dav: dav_type): char;
	procedure get_SCSI_parms(    SCSIdav:dav_type;
				 var SCSIdt:byte;
				 var SCSIRemovable:boolean;
				 var SCSImp:mp_type);


implement

type
	uep_type = ^unitentry;

	IsScsiCardType          = procedure(    sc:byte;
					    var yes:boolean);
	ScsiSBSizeType          = procedure(var size:integer);
	ScsiSBInitType          = procedure(    pSB:ANYPTR;  pUP:uep_type);
	ScsiCheckDevType        = procedure(    pSB:ANYPTR);
	ScsiDevInfoType         = procedure(    pSB:ANYPTR;
					    var DevType, AnsiVersion:integer;
					    var Removable:boolean;
					    var VendorString:String255);
	ScsiDiscSizeType        = procedure(    pSB:ANYPTR;
					    var NumBytesBlock, NumBlocksTrack,
						NumTracksCylinder, NumCylinders:integer);
	ScsiPreventType         = procedure(    pSB:ANYPTR);

	ScsiProcType            = packed record case integer of
						0:(value, slink:integer);
						1:(IsCard:IsScsiCardType);
						2:(SBSize:ScsiSBSizeType);
						3:(SBInit:ScsiSBInitType);
						4:(CheckDev:ScsiCheckDevType);
						5:(DevInfo:ScsiDevInfoType);
						6:(DiscSize:ScsiDiscSizeType);
						7:(Prevent:ScsiPreventType);
				  end;

var
	IsScsiCardProc,
	ScsiSBSizeProc,
	ScsiSBInitProc,
	ScsiCheckDevProc,
	ScsiDevInfoProc,
	ScsiDiscSizeProc,
	ScsiPreventProc:ScsiProcType;

	pSB:ANYPTR;
	pUnit:uep_type;
	SCSILIBinMemory:boolean;


procedure init_SCSIscanstuff;
var
	i:integer;
begin
	IsScsiCardProc.value            := value('SCSILIB_ISSCSICARD');
	ScsiSBSizeProc.value            := value('SCSILIB_SCSISBSIZE');
	ScsiSBInitProc.value            := value('SCSILIB_SCSISBINIT');
	ScsiCheckDevProc.value          := value('SCSILIB_SCSICHECKDEV');
	ScsiDevInfoProc.value           := value('SCSILIB_SCSIDEVINFO');
	ScsiDiscSizeProc.value          := value('SCSILIB_SCSIDISCSIZE');
	ScsiPreventProc.value           := value('SCSILIB_SCSIDISCPREVENT');

	SCSILIBinMemory :=      (IsScsiCardProc.value <> 0) and
				(ScsiSBSizeProc.value <> 0) and
				(ScsiSBInitProc.value <> 0) and
				(ScsiCheckDevProc.value <> 0) and
				(ScsiDevInfoProc.value <> 0) and
				(ScsiDiscSizeProc.value <> 0) and
				(ScsiPreventProc.value <> 0);

	if SCSILIBinMemory then
	begin
		call(ScsiSBSizeProc.SBSize, i);
		newbytes(pSB, i);
		newbytes(pUnit, sizeof(unitentry));
	end;
end;

procedure SetUnit(pUnit:uep_type; dav:dav_type);
begin
	with pUnit^ do
	begin
		sc := dav.sc;
		ba := dav.ba;
		du := dav.du;
		dv := dav.dv;
	end;
end;

function SCSIscanneddevice_letter(scan_dav: dav_type): char;
var
	b:boolean;
begin
	SCSIscanneddevice_letter := NODEVICE;  {until proven otherwise}
	if SCSILIBinMemory then
	begin
		call(IsScsiCardProc.IsCard, scan_dav.sc, b);
		if b then {this is a scsi card}
		begin
			SetUnit(pUnit, scan_dav);
			call(ScsiSBInitProc.SBInit, pSB, addr(scan_dav));
			call(ScsiCheckDevProc.CheckDev, pSB);
			if (ioresult = ord(inoerror)) or
			   (ioresult = ord(zmediumchanged)) or
			   (ioresult = ord(znotready)) then
				SCSIscanneddevice_letter := SCSI;
			ioresult := ord(inoerror);
		end;
	end;
end;


procedure get_SCSI_parms(    SCSIdav:dav_type;
			 var SCSIdt:byte;
			 var SCSIRemovable:boolean;
			 var SCSImp:mp_type);
label   1;
var
	dt, ansi:integer;
	s:string255;
	nbps, nspt, ntpc, nc:integer;
	DoPrevent:boolean;
begin
	DoPrevent := FALSE;
	if SCSIscanneddevice_letter(SCSIdav) = SCSI then
	begin
		call(ScsiDevInfoProc.DevInfo, pSB, dt, ansi, SCSIRemovable, s);
		if (ioresult <> ord(inoerror)) or (dt <> 0) then
			{error on communication or not a disk type}
			goto 1;
		SCSIdt := dt;
		if (SCSIRemovable) and (SCSIRemovableOption = AllAreHard) then
		begin
			SCSIRemovable := FALSE;
			DoPrevent := TRUE;
		end;
		call(ScsiDiscSizeProc.DiscSize, pSB, nbps, nspt, ntpc, nc);
		if ioresult = ord(inoerror) then
		begin
			SCSImp.tpm := ntpc * nc;
			SCSImp.bpt := nbps * nspt;
			if (SCSIRemovable) and
			   (SCSIRemovableOption = AllOver10MAreHard) and
			   ( (SCSImp.tpm * SCSImp.bpt) >= hex('A00000') ) then
			begin
				SCSIRemovable := FALSE;
				DoPrevent := TRUE;
			end;
		end
		else if SCSIRemovable then
		begin
			ioresult := ord(inoerror);
			SCSImp.tpm := 1;
			SCSImp.bpt := 256;
		end
		else
			goto 1;
	end
	else
	begin
		1:
		ioresult := ord(inoerror);
		DoPrevent := FALSE;
		SCSIdt := 255;
		SCSImp.tpm := 0;
		SCSImp.bpt := 0;
	end;

	if (DoPrevent) then
	begin
		call(ScsiPreventProc.Prevent, pSB);
		ioresult := ord(inoerror);
	end;
end;



end; {SCSIscanstuff}
$page$

{program ctable}

  (********************************************)
  (*               Caution:                   *)
  (* Modify this section only if the desired  *)
  (* configuration cannot be achieved by      *)
  (* modifying the OPTIONS module.            *)
  (********************************************)

import
  sysglobals, fs, ldr, options, ctr, BRstuff, scanstuff, SCSIscanstuff, bootDAMmodule;  {DEW - added SCSI}

const
  sysprefix = '/WORKSTATIONS/SYSTEM';
  null_dav =
    dav_type[sc: -1, ba: -1, du: -1, dv: -1];
  null_MSUS =
    MSUS_type[flpy_flags: assign_neither_flpy_unit, letter: NODEVICE, dav: null_dav];
  HP9885_default_MSUS =
    MSUS_type[flpy_flags: assign_neither_flpy_unit, letter: HP9885, dav: HP9885_default_dav];
  MSUS_array_size = 10;

type
  MSUS_array_type = array [1..MSUS_array_size] of MSUS_type;
  log_MSUS_options = (search_for_other_units, do_not_search_for_other_units);

var
  flpy_MSUS: MSUS_array_type;
  harddisc_MSUS: MSUS_array_type;
  CS80tape_MSUS: MSUS_array_type;
  scanner_MSUS: MSUS_type;

  local_printer_dav: dav_type;
  SRM_dav: dav_type;
  BUBBLE_dav: dav_type;

  index, select_code, bus_address, i, nvols: shortint; {LAF 870622}
  lun, lun1, lun2: unitnum;
  CS80dt: byte;
  CS80id: integer;
  CS80hardvols: shortint;
  SCSIdt: byte;
  SCSIRemovable:boolean;
  mp: mp_type;
  pp: pp_type;
  ok: boolean;



function increment_and_test_lun: boolean;
  begin {increment_and_test_lun}
    lun := lun+1;
    increment_and_test_lun := lun<=last_harddisc_lun;
  end; {increment_and_test_lun}
$page$

function unit_prefix_successful(dirname: fid): boolean;
  var
    unitnum: integer;
    kvid: vid;
  begin {unit_prefix_successful}
    doprefix(dirname, kvid, unitnum, true);
    unit_prefix_successful := ioresult=ord(inoerror);
  end; {unit_prefix_successful}


procedure zero_out_NA_fields(var device_MSUS: MSUS_type);
  const
    clear = true;
    retain = false;
  procedure zero_fields(sc, ba, du, dv: boolean);
    begin  {zero_fields}
      if sc then device_MSUS.dav.sc := 0;
      if ba then device_MSUS.dav.ba := 0;
      if du then device_MSUS.dav.du := 0;
      if dv then device_MSUS.dav.dv := 0;
    end;  {zero_fields}
  begin {zero_out_NA_fields}
    case device_MSUS.letter of
      INTERNAL:
	zero_fields({sc} clear , {ba} clear , {du} retain, {dv} clear );
      HP9885:
	zero_fields({sc} retain, {ba} clear , {du} retain, {dv} clear );
{INTERNAL ONLY BEGIN}
      HP9895, HP8290X, HP913X_A, HP913X_B, HP913X_C, HP7920, HP7925, SRM:
{EXTERNAL VERSION
      HP9895, HP8290X, HP913X_A, HP913X_B, HP913X_C, SRM:
{INTERNAL ONLY END}
	zero_fields({sc} retain, {ba} retain, {du} retain, {dv} clear );
      BUBBLE:
	zero_fields({sc} retain, {ba} clear , {du} clear , {dv} clear );
      EPROM:
	zero_fields({sc} clear , {ba} clear , {du} clear , {dv} retain);
      otherwise  {includes HP7905, HP7906, CS80, SCSI}
	{do nothing};
    end; {case}
  end; {zero_out_NA_fields}


procedure assign_flpy_unit_pair(lun: unitnum; dam: ds_type; index: shortint);
  begin {assign_flpy_unit_pair}
    with flpy_MSUS[index], flpy_flags, dav do
      begin
	if assign_even_unit then
	  begin
	    tea_flpy(lun, letter, dam, sc, ba, du);
	    lun := lun+1;
	  end; {if}
	if assign_odd_unit then
	  tea_flpy(lun, letter, dam, sc, ba, du+1);
      end; {with}
  end; {assign_flpy_unit_pair}
$page$

procedure log_MSUS(MSUS: MSUS_type; log_MSUS_option: log_MSUS_options);


  type
    log_flpy_MSUS_options = (assign_both_units, assign_only_this_unit);


  procedure log_specific_MSUS(var specific_MSUS: MSUS_array_type);
    var
      index: shortint;
      found: boolean;
    begin {log_specific_MSUS}
      index := 0;
      repeat
	index := index+1;
	found := MSUSs_match(specific_MSUS[index], MSUS);
      until found or (index=MSUS_array_size);
      if found
	then MSUS.flpy_flags := specific_MSUS[index].flpy_flags {preserve}
	else MSUS.flpy_flags := assign_neither_flpy_unit;       {initialize}
      while index>1 do
	begin
	  specific_MSUS[index] := specific_MSUS[index-1];
	  index := index-1;
	end;  {while}
      specific_MSUS[1] := MSUS;
    end; {log_specific_MSUS}


  procedure log_flpy_MSUS(log_flpy_MSUS_option: log_flpy_MSUS_options);
    var
      odd_unit: boolean;
    begin {log_flpy_MSUS}
      with MSUS.dav do
	begin  {since floppy units are assigned in pairs...}
	  odd_unit := odd(du);     {remember which unit this actually is...}
	  du := du-ord(odd_unit);  {but log only the even-numbered unit!}
	end; {with}
      log_specific_MSUS(flpy_MSUS);
      with flpy_MSUS[1] do  {update the flpy_flags}
	if log_flpy_MSUS_option=assign_both_units then
	  flpy_flags := assign_both_flpy_units
	else  {set only this unit's assignment flag}
	  if odd_unit
	    then flpy_flags.assign_odd_unit  := true
	    else flpy_flags.assign_even_unit := true;
    end; {log_flpy_MSUS}


  procedure log_harddisc_MSUS;
    begin {log_harddisc_MSUS}
      MSUS.dav.dv := 0;  {all vols will be assigned, so log only volume zero}
      log_specific_MSUS(harddisc_MSUS);
    end; {log_harddisc_MSUS}
$page$

  function any_9895_unit_missing: boolean;
    var
      temp_dav: dav_type;
      unit_missing: boolean;
    begin {any_9895_unit_missing}
      temp_dav := MSUS.dav;
      temp_dav.du := 3;  {start with unit 3 and work down}
      repeat  {see if all four units are present}
	unit_missing := scanneddevice_letter(temp_dav)<>HP9895;
	temp_dav.du := temp_dav.du-1;
      until (temp_dav.du<0) or unit_missing;
      any_9895_unit_missing := unit_missing;
    end; {any_9895_unit_missing}


  procedure search_higher_numbered_CS80_units;
    var
      temp_MSUS: MSUS_type;
    begin {search_higher_numbered_CS80_units}
      temp_MSUS := MSUS;
      with temp_MSUS, dav do
	if du<14 then  {potentially there are higher-numbered units}
	  begin
	    du := du+1;
	    dv := 0;  {always look for volume 0}
	    letter := scanneddevice_letter(dav);
	    log_MSUS(temp_MSUS, search_for_other_units);  {recurse!}
	  end; {if}
    end; {search_higher_numbered_CS80_units}


  procedure log_CS80_MSUS;
    var
      CS80dt: byte;             {device type}
      CS80id: integer;          {HP product number}
      CS80hardvols: shortint;   {number of volumes}
      CS80mp: mp_type;          {media parameters}
    const
      tape_dt = 2;
      min_hd_size = 10000000;  {bytes}
    begin {log_CS80_MSUS}
      get_CS80_parms(MSUS.dav, CS80dt, CS80id, CS80hardvols, CS80mp);
      if CS80dt=tape_dt then
	log_specific_MSUS(CS80tape_MSUS)
      else if (CS80hardvols=1) and (CS80mp.bpt*CS80mp.tpm<min_hd_size) then
	log_flpy_MSUS(assign_only_this_unit)
      else
	log_harddisc_MSUS;
    end; {log_CS80_MSUS}

  procedure search_higher_numbered_SCSI_units;          {DEW 09/89 - added SCSI support}
    var
      temp_MSUS: MSUS_type;
    begin {search_higher_numbered_SCSI_units}
      {
	search for multiple logical units on a given bus address
      }
      temp_MSUS := MSUS;
      with temp_MSUS, dav do
	if du<7 then
	  begin
	    du := du+1;
	    dv := 0;  {always look for volume 0}
	    letter := SCSIscanneddevice_letter(dav);
	    log_MSUS(temp_MSUS, search_for_other_units);  {recurse!}
	  end; {if}
    end; {search_higher_numbered_SCSI_units}


  procedure log_SCSI_MSUS;                              {DEW 09/89 - added SCSI support}
    var
      SCSIdt: byte;             {device type}
      SCSIRemovable: boolean;   {removable disk}
      SCSImp: mp_type;          {media parameters}
    begin {log_SCSI_MSUS}
      get_SCSI_parms(MSUS.dav, SCSIdt, SCSIRemovable, SCSImp);
      if SCSIdt = 0 then {disk type}
      begin
	if SCSIRemovable then
	  log_flpy_MSUS(assign_only_this_unit)
	else
	  log_harddisc_MSUS;
      end;
      {
	else tapes, printers, etc. not supported.
      }
    end; {log_SCSI_MSUS}
$page$

  begin {log_MSUS}

    zero_out_NA_fields(MSUS);

    case MSUS.letter of

      INTERNAL, HP8290X, HP9885:
	log_flpy_MSUS(assign_both_units);

{INTERNAL ONLY BEGIN}
      HP913X_A, HP913X_B, HP913X_C, HP7905, HP7906, HP7920, HP7925:
{EXTERNAL VERSION
      HP913X_A, HP913X_B, HP913X_C:
{INTERNAL ONLY END}
	log_harddisc_MSUS;

      HP9895:
	if any_9895_unit_missing then  {ultimately assign only two units }
	  log_flpy_MSUS(assign_both_units)
	else  {ultimately assign all four units (probably a 913X)}
	  begin
	    MSUS.dav.du := 0;  {log only unit zero}
	    log_harddisc_MSUS;
	  end;  {else}

      CS80:
	begin
	  if log_MSUS_option=search_for_other_units then
	    search_higher_numbered_CS80_units;
	  log_CS80_MSUS;  {distinguishes tapes, floppies, & hard discs!}
	end;

      SRM:
	SRM_dav := MSUS.dav;

      PRINTER:
	local_printer_dav := MSUS.dav;

      BUBBLE:
	BUBBLE_dav := MSUS.dav;

      SCSI:                                             {DEW 09/89 - added SCSI support}
	begin
	  if log_MSUS_option=search_for_other_units then
	    search_higher_numbered_SCSI_units;
	  log_SCSI_MSUS;  {only disks are supported right now}
	end;

      otherwise
	{do nothing};

    end; {case}

  end; {log_MSUS}
$page$

{
{ Return the suffix of the system we booted.
{ e.g. SYSTEM_xxx -> xxx
{      SYSxxxxxxx -> xxxxxxx
{ Used as suffix for sysprefix (/WORKSTATIONS/SYSTEM) when
{ setting system volume on HFS disks.
}
function syssuffix: string20;
begin
  syssuffix := bootname('', 0);
end;


{
{ determine whether a card at specified select code is 98629--SRM
{ added 870622 LAF to fix bug FSDat01185
{
{ added ability to connect up to SRMLAN support, if it exists and is
{ willing to support 98643A at select code sc. is_SRMcard will return
{ TRUE if it's SRM card, or 98643A with SRMLAN support. SFB/RDQ 1/19/89
}
function is_SRMcard(sc: integer): boolean;
const
  srmlan_symbol='LANSRM_LANSRM_OK';     {procedure in SRMLAN version of SRM}
type
  chararray = packed array [0..65535] of char;
  pchararray = ^chararray;
  proctrick_rectype = record case boolean of
	true  : (proc:procedure(var sc : integer));
	false : (entry, statlink: integer);
    end;
var
  card: pchararray;
  stat2addr: integer;
  kludgerec: record case integer of
    0: (int: integer);
    1: (adr: pchararray);
    end;
  proctrick : proctrick_rectype;
begin
try     (* recover if no card here or if not SRM *)
  is_SRMcard:=true;
  kludgerec.int := sc * hex('10000') + hex('600000');   (* card address *)
  card := kludgerec.adr;
  if ord(card^[1]) mod 128 = 52 then        (* datacomm ?? *)
    begin
      stat2addr := ord(card^[16395])*256 + ord(card^[16393]);
      if stat2addr >= 32768 then escape(0);
      if ord(card^[stat2addr*2+1]) mod 128 <> 1 then escape(0); (* not datacomm *)
      if ord(card^[hex('402f')]) <> 3 then escape(0);       (* not SRM *)
    end
  else
    begin
      proctrick.statlink:=0;
      proctrick.entry:=value(SRMLAN_SYMBOL);
      if proctrick.entry <> 0 then
	call(proctrick.proc, sc);       {SRMLAN_OK will set sc < 0 if will support
					 SRMLAN for this card.
					 Let SRMLAN_OK decide if card is 98643A}
      if sc >= 0 then escape(0);        {LANSRM will not support this sc}
    end;
recover
  is_SRMcard := false;
end;


begin {ctable}

  { various initializations }

  call(cleariohook); {init IO cards in case the BOOTROM drivers touched them}

  init_scanstuff;
  init_SCSIscanstuff;

  for index := 1 to MSUS_array_size do
    begin
      flpy_MSUS[index]     := null_MSUS;
      harddisc_MSUS[index] := null_MSUS;
      CS80tape_MSUS[index] := null_MSUS;
    end;  {for}

  SRM_dav                  := SRM_default_dav;     {overridden if bootdevice}

  BUBBLE_dav               := BUBBLE_default_dav;  {overridden if bootdevice}

  if local_printer_option=HPIB
    then local_printer_dav := local_HPIB_printer_default_dav   {scan may override}
    else if local_printer_option=RS232
    then local_printer_dav := local_RS232_printer_default_dav  {scan may override}
    else local_printer_dav := local_PARALLEL_printer_default_dav;  {scan may override}


  { log the default 9885 floppy pair, since HP-IB scanning won't include it }

  log_MSUS(HP9885_default_MSUS, search_for_other_units);


  { scan the HP-IB's for mass storage devices and possibly a local printer }

  with scanner_MSUS, dav do
    for index := 1 to sc_list_length do
      for bus_address := 0 to 7 do
	begin
	  sc := sc_list[index];
	  ba := bus_address;
	  du := 0;
	  dv := 0;
	  letter := scanneddevice_letter(dav);
	  log_MSUS(scanner_MSUS, search_for_other_units);
	end; {for}

  { scan the SCSI select codes for disks}

  with scanner_MSUS, dav do
    for index := 1 to SCSIsc_list_length do
      for bus_address := 0 to 7 do
	begin
	  sc := SCSIsc_list[index];
	  ba := bus_address;
	  du := 0;
	  dv := 0;
	  letter := SCSIscanneddevice_letter(dav);
	  log_MSUS(scanner_MSUS, search_for_other_units);
	end; {for}


  { log internal mini if present, since HP-IB scanning didn't include it }

  if internal_mini_present then
    log_MSUS(INTERNAL_MSUS, search_for_other_units);


  { check sc 21 for SRM, scan for it if it's not there, keep lowest sc }
  { added 870622 LAF to fix bug FSDat01185 }

  if not is_SRMcard(SRM_dav.sc) then
    for select_code:=31 downto 7 do
      if is_SRMcard(select_code) then
	SRM_dav.sc:=select_code;


  { get the bootdevice MSUS & log it }

  get_bootdevice_MSUS(bootdev_MSUS);
  zero_out_NA_fields(bootdev_MSUS);  {for tea routine comparisons}
  log_MSUS(bootdev_MSUS, do_not_search_for_other_units);
  bootdev_lun := 0;  {set otherwise if/when bootdevice is assigned in tea}
$page$

  { Create a temporary table & fill it with dummy entries }

  create_temp_unitable;


  { standard assignments: avoid changing }

  tea_memory_volume_dam(primary_dam);

  tea_crt( 1);
  tea_kbd( 2);

  assign_flpy_unit_pair( 3, primary_dam, {flpy_MSUS[]} 1);

  with SRM_dav do
    tea_srm( 5, sc, ba, du);

  with local_printer_dav do
    tea_local_printer( 6, sc, ba, {uvid} 'PRINTER', local_printer_timeout);


  { optional floppy unit pairs }

  for index := 2 to floppy_unit_pairs do
    assign_flpy_unit_pair(7+(index-2)*2, primary_dam, {flpy_MSUS[]} index);

$page$

  { local hard discs }

  $if true$

    lun := first_harddisc_lun-1;

    for index := 1 to MSUS_array_size do
      with harddisc_MSUS[index], dav do
	case letter of

	  HP9895: {9895 ident with all four units present; probably a HP913X}
	    for i := 0 to 3 do
	      if increment_and_test_lun then
		tea_HP9895(lun, primary_dam, sc, ba, {du} i, {block_offset} 0);

{INTERNAL ONLY BEGIN}
	  HP913X_A, HP913X_B, HP913X_C, HP7920, HP7925:
{EXTERNAL VERSION
	  HP913X_A, HP913X_B, HP913X_C:
{INTERNAL ONLY END}
	    begin
	      mp := medium_parameters(letter);
	      pp := partitioning_parameters(letter);
	      nvols := number_vols(mp, pp);
	      hfs_installed := false;
	      for i := 0 to nvols-1 do
		if not hfs_installed and increment_and_test_lun then
		  tea_amigo_sv(lun, primary_dam, sc, ba, du,
				    vol_offset(i, nvols, mp),
				    letter,
				    vol_bytes(i, nvols, mp));
	    end;

{INTERNAL ONLY BEGIN}
	  HP7905, HP7906:
	    begin
	      mp := medium_parameters(letter);
	      pp := partitioning_parameters(letter);
	      repeat
		nvols := number_vols(mp, pp);
		hfs_installed := false;
		for i := 0 to nvols-1 do
		  if not hfs_installed and increment_and_test_lun then
		    tea_amigo_mv(lun, primary_dam, sc, ba, du, dv,
				      vol_offset(i, nvols, mp),
				      letter,
				      vol_bytes(i, nvols, mp));
		if letter=HP7905 then  {adjust for its half-size fixed portion}
		  mp.tpm := mp.tpm div 2;
		dv := dv+1;
	      until dv>=2;
	    end;
{INTERNAL ONLY END}

	  CS80:
	    begin
	      pp := partitioning_parameters(letter);
	      repeat
		get_CS80_parms(dav, CS80dt, CS80id, CS80hardvols, mp);
		if mp.tpm=1 then  {track partitioning info unavailable...}
		  mp := block_boundaries(mp);  {will have to fake it!}
		nvols := number_vols(mp, pp);
		hfs_installed := false;
		for i := 0 to nvols-1 do
		  if not hfs_installed and increment_and_test_lun then
		    tea_CS80_mv(lun, primary_dam, sc, ba, du, dv,
				     vol_offset(i, nvols, mp),
				     {devid} CS80id,
				     vol_bytes(i, nvols, mp),
				     mp.tpm*mp.bpt);
		dv := dv+1;
	      until dv>=CS80hardvols;
	    end;

	  SCSI:
	    begin
		pp := partitioning_parameters(letter);
		get_SCSI_parms(dav, SCSIdt, SCSIRemovable, mp);
		nvols := number_vols(mp, pp);
		hfs_installed := false;
		for i := 0 to nvols-1 do
		  if not hfs_installed and increment_and_test_lun then
		    tea_SCSI_mv(lun, primary_dam, sc, ba, du, dv,
				     vol_offset(i, nvols, mp),
				     {devid} SCSIdt,
				     vol_bytes(i, nvols, mp),
				     mp.tpm*mp.bpt);
	    end;

	  otherwise
	    {no local hard disc logged};

	end; {case}

  $end$  { local hard discs }


  { CS80 tapes }

  $if true$

    with CS80tape_MSUS[1], dav do
      if letter=CS80 then
	tea_CS80_sv(41, LIF_dam, sc, ba, du, dv);

    with CS80tape_MSUS[2], dav do
      if letter=CS80 then
	tea_CS80_sv(42, LIF_dam, sc, ba, du, dv);

  $end$  { CS80 tapes }


  { secondary directory access method entries for highest priority floppies }

  assign_flpy_unit_pair(43, secondary_dam, {flpy_MSUS[]} 1);

  { secondary directory access method entries for additional floppies }

  assign_flpy_unit_pair(47, secondary_dam, {flpy_MSUS[]} 2);

  assign_flpy_unit_pair(49, secondary_dam, {flpy_MSUS[]} 3);



  { duplicate entries for prefixing down the SRM }

{INTERNAL ONLY BEGIN}
  (***********************************************************************)
  (*  NOTE:  Additional duplicate SRM entries may be assigned here, then *)
  (*    prefixed down below after assigning the temp_unitable.  However  *)
  (*    for correct behavior in assigning the system unit, specifically  *)
  (*    if booting off the SRM, unit #45 must be the assigned AFTER all  *)
  (*    the other SRM units have been assigned!                          *)
  (*                                                                     *)
  (*    You may assign both "real" SRM and SRM-UX units with this code.  *)
  (*    You must put in the correct unit number, select code, bus        *)
  (*    address (really SRM host node number), and du (really SRM disc   *)
  (*    volume number or SRM-UX emulated disc volume number.)            *)
  (*                                                                     *)
  (*    Unit numbers 46 through 50 are often available for use as        *)
  (*    additional SRM or SRM-UX entries, especially if you have no      *)
  (*    more than one floppy unit pair, and you are not booting from an  *)
  (*    HFS hard disc.                                                   *)
  (*                                                                     *)
  (*    SRM volume information is available from the SRM console.        *)
  (*    SRM-UX volume emulation information is available from the        *)
  (*    HP-UX file "/etc/srmconf" on the SRM-UX server machine.          *)
  (***********************************************************************)
{INTERNAL ONLY END}

  with SRM_dav do
    begin
      {  tea_srm(46, sc, ba, du);  {free unless booting from HFS hard disc}
      tea_srm(45, sc, ba, du);  {for possible use as the system unit}
    end; {with}

$page$

  { templates for "manually" specifying mass storage table entry assignments }


  $if false$ { internal minifloppy in a 9826/9836 }
    tea_mini( 3, primary_dam, {du} 0);
    tea_mini( 4, primary_dam, {du} 1);
  $end$

  $if false$ { HP8290X, HP9121, or the floppy in an HP913X }
    tea_HP8290X( 3, primary_dam, {sc}  7, {ba} 0, {du} 0);
    tea_HP8290X( 4, primary_dam, {sc}  7, {ba} 0, {du} 1);
  $end$

  $if false$ { HP9895 }
    tea_HP9895( 7, primary_dam, {sc}  7, {ba} 0, {du} 0, {block_offset} 0);
    tea_HP9895( 8, primary_dam, {sc}  7, {ba} 0, {du} 1, {block_offset} 0);
  $end$

  $if false$ { HP913X (four volume 9895 look-a-like version) }
    for i := 0 to 3 do
      tea_HP9895(11+i, primary_dam, {sc}  7, {ba} 0, {du} i, {block_offset} 0);
  $end$

  $if false$ { HP913X_A (5 Mbyte single volume version) }
    mp := medium_parameters(HP913X_A);
    nvols := 4;
    for i := 0 to nvols-1 do
      tea_amigo_sv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0,
			 vol_offset(i, nvols, mp),
			 HP913X_A,
			 vol_bytes(i, nvols, mp));
  $end$

  $if false$ { HP913X_B (10 Mbyte single volume version) }
    mp := medium_parameters(HP913X_B);
    nvols := 9;
    for i := 0 to nvols-1 do
      tea_amigo_sv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0,
			 vol_offset(i, nvols, mp),
			 HP913X_B,
			 vol_bytes(i, nvols, mp));
  $end$

  $if false$ { HP913X_C (15 Mbyte single volume version) }
    mp := medium_parameters(HP913X_C);
    nvols := 14;
    for i := 0 to nvols-1 do
      tea_amigo_sv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0,
			 vol_offset(i, nvols, mp),
			 HP913X_C,
			 vol_bytes(i, nvols, mp));
  $end$
$page$

{INTERNAL ONLY BEGIN}
  $if false$ { HP7905 }
    mp := medium_parameters(HP7905);
    { mp := block_boundaries(mp);  {override track boundary partitioning}
    nvols := 10;
    for i := 0 to nvols-1 do  {assign removable medium entries}
      tea_amigo_mv (11+i, primary_dam, {sc} 14, {ba} 0, {du} 0, {dv} 0,
			  {offset} vol_offset(i, nvols, mp),
			  {letter} HP7905,
			  {umaxbytes} vol_bytes(i, nvols, mp));
    mp.tpm := mp.tpm div 2;  {fixed only half size}
    nvols := 5;
    for i := 0 to nvols-1 do  {assign fixed medium entries}
      tea_amigo_mv (21+i, primary_dam, {sc} 14, {ba} 0, {du} 0, {dv} 1,
			  {offset} vol_offset(i, nvols, mp),
			  {letter} HP7905,
			  {umaxbytes} vol_bytes(i, nvols, mp));
  $end$

  $if false$ { HP7906 }
    mp := medium_parameters(HP7906);
    { mp := block_boundaries(mp);  {override track boundary partitioning}
    nvols := 10;
    for i := 0 to nvols-1 do  {assign removable medium entries}
      tea_amigo_mv (11+i, primary_dam, {sc} 14, {ba} 0, {du} 0, {dv} 0,
			  {offset} vol_offset(i, nvols, mp),
			  {letter} HP7906,
			  {umaxbytes} vol_bytes(i, nvols, mp));
    for i := 0 to nvols-1 do  {assign fixed medium entries}
      tea_amigo_mv (21+i, primary_dam, {sc} 14, {ba} 0, {du} 0, {dv} 1,
			  {offset} vol_offset(i, nvols, mp),
			  {letter} HP7906,
			  {umaxbytes} vol_bytes(i, nvols, mp));
  $end$

  $if false$ { HP7920 }
    mp := medium_parameters(HP7920);
    { mp := block_boundaries(mp);  {override track boundary partitioning}
    nvols := 30;
    for i := 0 to nvols-1 do
      tea_amigo_sv(11+i, primary_dam, {sc} 14, {ba} 0, {du} 0,
			 {offset} vol_offset(i, nvols, mp),
			 {letter} HP7920,
			 {umaxbytes} vol_bytes(i, nvols, mp));
  $end$

  $if false$ { HP7925 }
    mp := medium_parameters(HP7925);
    { mp := block_boundaries(mp);  {override track boundary partitioning}
    nvols := 30;
    for i := 0 to nvols-1 do
      tea_amigo_sv(11+i, primary_dam, {sc} 14, {ba} 0, {du} 0,
			 {offset} vol_offset(i, nvols, mp),
			 {letter} HP7925,
			 {umaxbytes} vol_bytes(i, nvols, mp));
  $end$
{INTERNAL ONLY END}
$page$

  $if false$ { current CS/80 discs "soft" partitioned by the host }
      CS80id := 7908; nvols := 16; mp.tpm :=  5* 370; mp.bpt := 35*256;  {7908}
    { CS80id := 7911; nvols := 27; mp.tpm :=  3* 572; mp.bpt := 64*256;  {7911}
    { CS80id := 7912; nvols := 30; mp.tpm :=  7* 572; mp.bpt := 64*256;  {7912}
    { CS80id := 7914; nvols := 30; mp.tpm :=  7*1152; mp.bpt := 64*256;  {7914}
    { CS80id := 7933; nvols := 30; mp.tpm := 13*1321; mp.bpt := 92*256;  {7933}
    { CS80id := 7935; nvols := 30; mp.tpm := 13*1321; mp.bpt := 92*256;  {7935}
    { mp := block_boundaries(mp);  {override track boundary partitioning}
    hfs_installed:=false;
    for i := 0 to nvols-1 do
      if not hfs_installed then
	tea_CS80_mv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0, {dv} 0,
			  vol_offset(i, nvols, mp),
			  {devid} CS80id,
			  vol_bytes(i, nvols, mp),
			  mp.tpm*mp.bpt);
  $end$


  $if false$ { current CS/80 discs "hard" partitioned by the device }
      CS80hardvols :=  3;
      for i := 0 to CS80hardvols-1 do
	tea_CS80_sv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0, {dv} i);
  $end$


  $if false$ { Command Set/80 floppy }
    tea_CS80_sv( 3, primary_dam, {sc}  7, {ba} 0, {du} 0, {dv} 0);
  $end$


  $if false$ { Command Set/80 tape }
    tea_CS80_sv(41, LIF_dam, {sc}  7, {ba} 0, {du} 1, {dv} 0);
  $end$


  $if false$ { BUBBLE memory }
    {watch for conflicting uses of unit 42}
    {BUBBLE_DAV.SC default is 30 but may have been changed to boot SC}
    tea_BUBBLE(42,primary_dam,BUBBLE_dav.SC);
  $end$


  $if false$ { EPROM DISC }
    {watch for conflicting uses of unit 42}
    tea_EPROM(42,primary_dam,{ sequence number } 0);
  $end$


  { end of templates }
$page$

  { assign the new unitable and unitclear all units }

  assign_temp_unitable;

  { prefix the primary and secondary SRM unit entries }

  if not unit_prefix_successful('#5:/') then
    {do nothing};  {tries to set up uvid for possible default unit assignment below}

  { if not unit_prefix_successful('#46:/?') then zap_assigned_unit(46);}
  {NOTE: DO NOT UNCOMMENT THE ABOVE LINE IF YOU BOOT FROM AN HFS DISC! }

  if not unit_prefix_successful('#45:'+sysprefix+srmnode(unitable^[45].sc)) then
    if not unit_prefix_successful('#45:'+sysprefix) then
      zap_assigned_unit(45);


  { remove extraneous local hard disc entries if necessary }

  lun2 := first_harddisc_lun;
  while lun2<last_harddisc_lun do
    begin
      lun1 := lun2;
      repeat
	lun2 := lun2+1;
      until (lun2>last_harddisc_lun) or not on_same_medium(lun1, lun2);
      pp := partitioning_parameters(unitable^[lun1].letter);
      if pp.mnv<-1 then
	remove_extraneous_volumes(lun1, lun2-1);
    end; {while}


  { assign the system unit }

  if specified_system_unit<>0 then
    ok := sysunit_ok(specified_system_unit)
  else if (bootdev_lun<>0) and (unitable^[bootdev_lun].umaxbytes>300000) then
    ok := sysunit_ok(bootdev_lun)
  else  {search for a more suitable system unit}
    begin
      index := 0;
      repeat
	index := index+1;
	ok := sysunit_ok(sysunit_list[index]);
      until ok or (index>=sysunit_list_length);
      if not ok then  {revert back to boot device, hoping it was identified}
	ok := sysunit_ok(bootdev_lun);
    end; {else}


  { special case for default unit assignment }

  if sysunit=45 then  {set the default unit to the primary SRM unit entry}
    dkvid := unitable^[5].uvid;
$page$
  { rearrange things for HFS }
  if h_unitable <> nil then with h_unitable^ do begin

      { if booted from HFS, need to reset syvid and dkvid       }
      { also, try to set sysvolume to #46:/WORKSTATIONS/SYSTEM*  }
      if unitable^[sysunit].uisfixed
      and tbl[sysunit].is_hfsunit
      and sysunit_ok(sysunit) then begin
	lun := sysunit;
	extra_HFS_unit(sysunit, 46, sysprefix+syssuffix);
	if not tbl[46].is_hfsunit then
	  extra_HFS_unit(sysunit, 46, sysprefix);
	if tbl[46].is_hfsunit and sysunit_ok(46) then
	  dkvid := unitable^[lun].uvid;
      end;

      { At this point, there is only one HFS unit per disc, except    }
      { on the system disc (if it's HFS), where there are two -- one  }
      { at /WORKSTATIONS/SYSTEM, the other at /.  Add more as         }
      { follows:                                                      }
      { extra_HFS_unit(old unit #, new unit #, prefix)                }
      { "new unit" then becomes a unit on the same disc as "old unit",}
      { which must already exist.  This fails unless new unit is not  }
      { yet used, or if the prefix fails.  The prefix should not in-  }
      { clude a volume name or number.                                }
      { Example:                                                      }
      {         extra_HFS_unit(11, 12, '/PROGS');                     }

  end;

  { re-open the standard system files }
  openfiles;

end. {ctable}
@


55.1
log
@Automatic bump of revision number for PWS version 3.25A
@
text
@@


54.3
log
@
pws2rcs automatic delta on Wed Aug 21 10:27:27 MDT 1991
@
text
@@


54.2
log
@
pws2rcs automatic delta on Wed Aug 21 09:35:48 MDT 1991
@
text
@d1 2657
@


54.1
log
@Automatic bump of revision number for PWS version 3.24
@
text
@a0 2657
					       (*

 (c) Copyright Hewlett-Packard Company 1983,
1984, 1985, 1987, 1989, 1990, 1991.
All rights are reserved.  Copying or other
reproduction of this program except for archival
purposes is prohibited without the prior
written consent of Hewlett-Packard Company.


	    RESTRICTED RIGHTS LEGEND

Use, duplication, or disclosure by the U.S. Government
is subject to restrictions as set forth in
subdivision (b)(3)(ii) of the Rights in Technical
Data and Computer Software clause at 52.227-7013.
Hewlett-Packard Company, 3000 Hanover Street,
Palo Alto CA 94304
						 *)


$page, sysprog$
$ALLOW_PACKED ON$ { JWS 4/10/85 }
$partial_eval on$

(********************************************************)
(*                                                      *)
(*  Note: You will need to use one of the following     *)
(*  compiler directives if the 'INTERFACE'              *)
(*  file is not in your current LIBRARY.                *)
(*  Choose the appropriate volume name  for             *)
(*  your configuration. If you are using                *)
(*  double-sided 3-1/2" media, the INTERFACE            *)
(*  file will be found on the ACCESS: volume.           *)
(*                                                      *)
(*  $search  'CONFIG:INTERFACE.'$                       *)
(*  $search  'ACCESS:INTERFACE.'$                       *)
(*                                                      *)
(********************************************************)

program {self-configuring} ctable;

module options;

  (********************************************)
  (* Choose the desired configuration options *)
  (* by editing the CONSTant declarations in  *)
  (* this module.                             *)
  (********************************************)

import
  sysglobals;

export

{INTERNAL ONLY BEGIN}
{ All internal-only code begins and ends as above and below.
{ MKCTBETA creates customer version from this internal source,
{ and it requires exactly the same spacing and capitalization
{ as in this example.  If there is an external version of
{ some code, it is introduced in an internal block like this
{EXTERNAL VERSION
{INTERNAL ONLY END}

{two possible versions of TABLE}
  const
    hfsversion  = 2;    { LIF primary DAM, HFS secondary }
    ucsdversion = 1;    { LIF primary DAM, UCSD secondary }

{change this assignment to get different versions}
  const
    thisversion = hfsversion;

{power-up system unit}
  const
    specified_system_unit =
      0;  {<>0 overrides auto-assignment}


{floppy/harddisc unit number slot tradeoff's}
  const
    floppy_unit_pairs =  {[1..10]}
      3;
    first_harddisc_lun = {do not edit!}
      7+(floppy_unit_pairs-1)*2;
    last_harddisc_lun =
      40;

$page$

{local printer type option}
  type
    local_printer_type = (HPIB, RS232, PARALLEL); {12/89 DEW - added PARALLEL}
  const
    local_printer_option = HPIB;


{local printer timeout}
  {
    maximum allowed delay between any two bytes:
      >0  specifies milliseconds (up to one hour)
      =0  specifies infinite timeout

    recommended values:
      -  HP2630 series  (HP-IB)       3000
      -  HP2670 series  (HP-IB)       3000
      -  HP9876         (HP-IB)       7000
      -  HP82905        (HP-IB)      12000
    Note: the HP82905 is currently NOT supported
      due to its improper response to interface
      clear (IFC), and its incompatible graphics
      dump sequence.

      -  HP LaserJet    (PARALLEL)   10000
  }
  const
    local_printer_timeout =
      $IF local_printer_option=HPIB$
	12000;  {milliseconds}
      $END$
      $IF local_printer_option=RS232$
	0;      {infinite}
      $END$
      $IF local_printer_option=PARALLEL$
	10000;  {milliseconds}
      $END$


{default dav's for devices not found by scanning}
  type
    dav_type = {device address vector}
      packed record
	sc, ba, du, dv: -128..127;
      end;
  const
    HP9885_default_dav =
      dav_type[sc: 12, ba: -1, du:  0, dv: -1];
    SRM_default_dav =
      dav_type[sc: 21, ba: {node} 0,
	       du: {unit} 8, dv: -1];
    BUBBLE_default_dav =
      dav_type[sc: 30, ba:  0, du:  0, dv:  0];
    local_HPIB_printer_default_dav =
      dav_type[sc:  7, ba:  1, du: -1, dv: -1];
    local_RS232_printer_default_dav =
      dav_type[sc:  9, ba:  0, du: -1, dv: -1];
    local_PARALLEL_printer_default_dav =
      dav_type[sc:  23, ba:  0, du: -1, dv: -1];

$page$

{local hard disc partitioning parameters}
  type
    pp_type =  {partitioning parameters}
      record
	mvs: integer;   {min vol size in bytes}
	mnv: shortint;  {max number of volumes}
      end;
  {   In general, MNV puts an upper bound on the
    number of logical volumes that a physical
    volume can be partitioned into.  Depending
    upon MNV's range, however, several types of
    behavior can occur.
      If MNV=0, then no logical volumes will ever
    be assigned for the device.
      If abs(MNV)=1, then exactly one logical
    volume will be assigned per physical volume
    of the device.  This corresponds to the
    2.X CTABLE's "single_volume" mode.
      If MNV>1, then partitioning will always be
    performed, subject to meeting the minimum
    volume size restrictions.  This corresponds
    to the 2.X CTABLE's "multi_volume" mode.
      If MNV<-1, then partitioning will be
    performed, but afterwards any logical volume
    that does not contain a valid directory will
    be coalesced with a previous adjacent logical
    volume if that one DOES contain a valid
    directory. As an extreme case, if only a
    single directory exists, and it is at the
    beginning of the physical volume, then all
    following logical volumes will be coalesced
    with the first, providing the same behavior
    as the 2.X CTABLE's "auto_volume" mode. With
    the less extreme cases, a wide variety of
    partitioning options are now possible without
    modification to CTABLE.                     }
  const
    min_size = {in bytes [1..maxint]}
      1000000;
    max_vols = {[-30..30]; <0 means autocoalesce}
      -30;
    HP913X_A_pp =
      pp_type[mvs: min_size, mnv: max_vols];
    HP913X_B_pp =
      pp_type[mvs: min_size, mnv: max_vols];
    HP913X_C_pp =
      pp_type[mvs: min_size, mnv: max_vols];
{INTERNAL ONLY BEGIN}
    HP7905_pp =  {historical value of mvs}
      pp_type[mvs:   983040, mnv: max_vols];
    HP7906_pp =  {historical value of mvs}
      pp_type[mvs:   983040, mnv: max_vols];
    HP7920_pp =
      pp_type[mvs: min_size, mnv: max_vols];
    HP7925_pp =
      pp_type[mvs: min_size, mnv: max_vols];
{INTERNAL ONLY END}
    CS80disc_pp =
      pp_type[mvs: min_size, mnv: max_vols];
    SCSIdisc_pp =                                {DEW 9/89 - added SCSI support}
      pp_type[mvs: min_size, mnv: max_vols];
$page$

{system unit auto-search declarations}
  const
    sysunit_list_length =
      7;
  type
    sysunit_list_type =
      array[1..sysunit_list_length] of unitnum;
  const
    sysunit_list =
      sysunit_list_type[
	  first_harddisc_lun, {first hard disc logical unit number}
	  45,   {srm, prefixed to user's sysvol}
	  4,    {floppy unit 1, primary DAM}
	  44,   {floppy unit 1, secondary DAM}
	  3,    {floppy unit 0, primary DAM}
	  43,   {floppy unit 0, secondary DAM}
	  42];  {bubble}


{HP-IB select code scanning declarations}
  const
    sc_list_length =
      3;
  type
    sc_list_type =
      array[1..sc_list_length] of shortint;
  const
    sc_list =
      sc_list_type[
	  7,    {internal HP-IB}
	  8,    {default sc for HP98624 HP-IB}
	  14];  {default sc for HP98625 HP-IB}

{SCSI select code scanning declarations}
  const
    SCSIsc_list_length =
      3;
  type
    SCSIsc_list_type =
      array[1..SCSIsc_list_length] of shortint;
  const
    SCSIsc_list =
      SCSIsc_list_type[
	  14,    {default sc for HP98265A (internal) and HP98658A (external)}
	  15,    {external SCSI sc when internal HP-IB/SCSI present at sc 14}
	  28];   {internal SCSI on 340/345}

{
  SCSI removable media may be an optical disk which has capacities of
  greater than 300Meg!  Therefore removable media can be configured to
  be:
	1:  A Hard disk if it has a size greater than 10M.
	2:  A Hard disk always.
	3:  A Floppy disk always.


  Things to be aware of when SCSI removable media is being treated like a
  hard disk:

    1: If the removable media is not on line at the time CTABLE is executed,
       the size of the disk is not available.  If the AllAreHard option is
       being used, then a unit entry will NOT be created for it.  If the
       AllOver10MAreHard option is used, then a unit entry for a floppy disk
       will be created for it.

    2: CTABLE will attempt the PREVENT MEDIUM REMOVAL command.  Through the
       SCSI programmer's interface, the ALLOW MEDIUM REMOVAL command may be
       sent.

    3: If the removable media goes off line for any reason, such as removing
       the media, PWS will discontinue communication with that device until
       CTABLE has been rerun.
}
   type
	SCSIRemovableOptionsType = (AllOver10MAreHard,
				    AllAreHard,
				    AllAreFloppy);
   const
	SCSIRemovableOption = AllOver10MAreHard;



implement {options}

end; {options}
$page, range off, ovflcheck off, partial_eval on$

module ctr; {ctable routines}

  (********************************************)
  (*                                          *)
  (*               Warning:                   *)
  (*   This module should not be modified!    *)
  (*                                          *)
  (********************************************)

import
  sysglobals, loader, options, ldr, fs, bootdammodule;

export

  const {mass storage letter specifiers}
    INTERNAL  = 'M';
    HP8290X   = 'N';
    HP9885    = 'F';
    HP9895    = 'H';
    HP913X_A  = 'U';
    HP913X_B  = 'V';
    HP913X_C  = 'W';
{INTERNAL ONLY BEGIN}
    HP7905    = 'Y';
    HP7906    = 'C';
    HP7920    = 'P';
    HP7925    = 'X';
{INTERNAL ONLY END}
    CS80      = 'Q';
    SRM       = 'G';
    PRINTER   = 'J';
    RAM       = 'R';
    BUBBLE    = 'B';
    EPROM     = 'E';
    SCSI      = 'S';      {DEW 09/89 - added SCSI support}
    NODEVICE  = #255;


  type
    flpy_flags_type = {flags governing floppy unit pair assignments}
      packed record
	assign_even_unit, assign_odd_unit: boolean;
      end;

  const
    assign_neither_flpy_unit =
      flpy_flags_type[assign_even_unit: false, assign_odd_unit: false];
    assign_both_flpy_units =
      flpy_flags_type[assign_even_unit: true, assign_odd_unit: true];

  type
    MSUS_type = {Mass Storage Unit Specifier}
      record
	flpy_flags: flpy_flags_type;
	letter: char;  {from the above mass storage letter specifiers}
	dav: dav_type;
      end;
$page$

    mp_type =  {medium parameters}
      record
	tpm: integer;  {tracks per medium}
	bpt: integer;  {bytes per track}
      end;

    ds_type =  {Directory access method Specifier for local mass storage}
      ( primary_dam,     {normally LIF }
	secondary_dam,   {HFS or UCSD, depending on choice in options}
	LIF_dam,         {LIF, regardless of primary/secondary choice}
	UCSD_dam,        {UCSD, regardless of primary/secondary choice}
	HFS_dam   );     {HFS, regardless of primary/secondary choice}

  var
    bootdev_MSUS: MSUS_type;
    bootdev_lun: unitnum;
    hfs_installed: boolean;

  procedure create_temp_unitable;
  procedure assign_and_clear_unit(lunit: unitnum);
  procedure assign_temp_unitable;
  function sysunit_ok(system_unit: unitnum): boolean;
  procedure zap_assigned_unit(lunit: unitnum);
  function on_same_medium(lun1, lun2: unitnum): boolean;
  procedure remove_extraneous_volumes(first_lun, last_lun: unitnum);
  function medium_parameters(letter: char): mp_type;
  function partitioning_parameters(letter: char): pp_type;
  function number_vols(mp: mp_type; pp: pp_type): shortint;
  function svol_bytes(letter: char): integer;
  function vol_bytes(current_vol, number_vols: shortint; mp: mp_type): integer;
  function vol_offset(current_vol, number_vols: shortint; mp: mp_type): integer;
  function block_boundaries(mp: mp_type): mp_type;
  function value(symbol: string255): integer;
  function MSUSs_match(MSUS1, MSUS2: MSUS_type): boolean;
  procedure extra_HFS_unit(oldun, newun: unitnum; prefix: string255);
  procedure install_HFS(un: unitnum; force: boolean);



  { table entry assignment procedures }

  procedure tea_memory_volume_dam(ds:ds_type);
  procedure tea_boot(un:unitnum);
  procedure tea_srm(un:unitnum;sc,ba,du:shortint);
  procedure tea_crt(un:unitnum);
  procedure tea_kbd(un:unitnum);
  procedure tea_local_printer(un:unitnum;sc,ba:shortint;uvid:vid;bto:integer);
  procedure tea_mini(un:unitnum;ds:ds_type;du:shortint);
  procedure tea_HP9885(un:unitnum;ds:ds_type;sc,du,block_os:shortint);
  procedure tea_HP9895(un:unitnum;ds:ds_type;sc,ba,du,block_os:shortint);
  procedure tea_HP8290X(un:unitnum;ds:ds_type;sc,ba,du:shortint);
  procedure tea_flpy(un:unitnum;lr:char;ds:ds_type;sc,ba,du:shortint);
{INTERNAL ONLY BEGIN}
  procedure tea_amigo_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;os:integer;lr:char;mb:integer);
{INTERNAL ONLY END}
  procedure tea_amigo_sv(un:unitnum;ds:ds_type;sc,ba,du:shortint;os:integer;lr:char;mb:integer);
  procedure tea_CS80_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;
					    os,id,mb,disksize:integer);
  procedure tea_CS80_sv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint);
  procedure tea_BUBBLE(un:unitnum;ds:ds_type;sc:shortint);
  procedure tea_EPROM(un:unitnum;ds:ds_type;sn:shortint);
  procedure tea_SCSI_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;
					    os,id,mb,disksize:integer); {DEW 09/89 - added SCSI support}
  procedure tea_SCSI_sv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint);    {DEW 09/89 - added SCSI support}
$page$

implement {ctr}

const  {abbreviation for tea procedure calls}
  T = true;
  F = false;

const  {actual driver entry point names}
  NO_DAM_name         = 'INITUNITS_NODAM';
  BOOT_DAM_name       = 'BOOTDAMMODULE_BOOTDAM';
  LIF_DAM_name        = 'LIFMODULE_LIFDAM';
  UCSD_DAM_name       = 'UCSDMODULE_UCSD_DAM';
  UNBLOCKED_DAM_name  = 'MISC_UNBLOCKEDDAM';
  SRM_DAM_name        = 'SRMDAMMODULE_SRMDAM';
  HFS_DAM_name        = 'HFS_DAM_MODULE_HFSDAM';

  NULL_TM_name        = 'INITUNITS_NOUNIT';
  BOOT_TM_name        = 'BOOTDAMMODULE_BOOTTM';
  CRT_TM_name         = 'SYSDEVS_CRTIO';
  KBD_TM_name         = 'SYSDEVS_KBDIO';
  MINI_TM_name        = 'MINI_MINIIO';
  SRM_TM_name         = 'SRMAMMODULE_SRMAM';
  PRINTER_TM_name     = 'PRTDVR_PRTIO';
  F9885_TM_name       = 'F9885DVR_F9885IO';
  AMIGO_TM_name       = 'AMIGODVR_AMIGOIO';
  CS80_TM_name        = 'CS80DVR_CS80IO';
  BUBBLE_TM_name      = 'BUBBLE_BUB_TM';
  EPROM_TM_name       = 'EPROMS_EPROM_TM';
  HFS_TM_name         = 'HFS_TM_MODULE_HFSTM';
  SCSIDSC_TM_name     = 'SCSIDISCMODULE_SCSIDISC';{09/89 DEW - added SCSI support}


var
  temp_unitable: unitableptr;
  temp_h_unitable: ^h_unitabletype;

procedure delay_timer(t:integer); external; {JWS 6/16/87}

procedure swap_h_units(u: unitnum);
  var
    t_unit: h_unittype;
  begin
    t_unit := h_unitable^.tbl[u];
    h_unitable^.tbl[u] := temp_h_unitable^.tbl[u];
    temp_h_unitable^.tbl[u] := t_unit;
  end;

procedure check(parameter, lower_bound, upper_bound: integer);
  begin
    if (parameter<lower_bound) or (parameter>upper_bound) then
      halt(-8) {value range error}
  end;

$page$

function value(symbol: string255): integer;
  var
    modp: moddescptr;
    ptr, valueptr: addrec;
    found: boolean;
  begin {value}
    value := 0;
    found := false;
    modp := sysdefs;
    while (modp<>nil) and not found do
      with modp^ do
	begin
	  ptr := defaddr;
	  while (ptr.a<defaddr.a+defsize) and not found do
	    begin
	      found := ptr.syp^=symbol;
	      ptr.a := ptr.a+strlen(ptr.syp^)+1;
	      ptr.a := ptr.a+ord(odd(ptr.a));
	      valueptr.a := ptr.a+2;
	      if found then
		value := valueptr.vep^.value;
	      ptr.a := ptr.a+ptr.gvp^.short;
	    end; {while}
	  modp := link;
	end; {with modp^}
  end; {value}


function MSUSs_match(MSUS1, MSUS2: MSUS_type): boolean;
  begin {MSUSs_match}
    MSUSs_match := (MSUS1.letter = MSUS2.letter) and
		   (MSUS1.dav.sc = MSUS2.dav.sc) and
		   (MSUS1.dav.ba = MSUS2.dav.ba) and
		   (MSUS1.dav.du = MSUS2.dav.du) and
		   (MSUS1.dav.dv = MSUS2.dav.dv);
  end; {MSUSs_match}

{
{ Make a new unit table entry at newun (must be free).
{ The medium is the same as oldun (must be HFS).
{ Prefix the new unit to the given directory name.
}
procedure extra_HFS_unit(oldun, newun: unitnum; prefix: string255);
  label
    999;
  var
    old_h_unit: h_unittype;
    old_unit: unitentry;
    i, un: integer;
    kvid: vid;
    dirname: fid;
  begin
    { new unit must be unused }
    if unitable^[newun].letter <> #0 then
      goto 999;

    { old unit must be HFS }
    if h_unitable = NIL then    {protect against ^nil. SFB}
     goto 999;

    if not h_unitable^.tbl[oldun].is_hfsunit then
      goto 999;

    { save unitable, h_unitable entries at new unit }
    old_unit := unitable^[newun];
    old_h_unit := h_unitable^.tbl[newun];

    { make newun and oldun look the same }
    unitable^[newun] := unitable^[oldun];
    h_unitable^.tbl[newun] := h_unitable^.tbl[oldun];

    { do the prefix }
    setstrlen(dirname, 0);
    strwrite(dirname, 1, i, '#', newun:1, ':', prefix);
    doprefix(dirname, kvid, un, true);

    { if it failed, reset the new unit }
    if ioresult <> ord(inoerror) then begin
      unitable^[newun] := old_unit;
      h_unitable^.tbl[newun] := old_h_unit;
    end;

  999:
  end;

{
{ Install HFS on this unit.
{ force -> install HFS always
{ not force -> install HFS if superblock is there
}
procedure install_HFS(un: unitnum; force: boolean);
  var
    dam_proc:
      packed record case integer of
	0: (dam: damtype);
	1: (value, slink: integer);
      end;

    tm_proc:
      packed record case integer of
	0: (tm: amtype);
	1: (value, slink: integer);
      end;
  begin
    if h_unitable <> nil then with h_unitable^ do begin
      call(init_unit_proc, un, force);
      { not force -> init_unit_proc sets is_hfsunit if recognized }
      if force or tbl[un].is_hfsunit then begin
	dam_proc.value := value(HFS_DAM_name);
	dam_proc.slink := 0;
	tm_proc.value := value(HFS_TM_name);
	tm_proc.slink := 0;
	with unitable^[un] do begin
	  dam := dam_proc.dam;
	  tm := tm_proc.tm;
	  uvid := '';
	end;
      end;
    end;
  end;


$page$

procedure tea {lowest-level Table Entry Assignment procedure}
    ( un:unitnum;                  {unit number}
      dam_name: string255;         {directory access method}
      tm_name: string255;          {transfer method (driver)}
      p_sc: shortint;              {select code}
      p_ba: shortint;              {bus address}
      p_du: shortint;              {disc unit}
      p_dv: shortint;              {disc volume}
      p_byteoffset: integer;       {physical starting byte of volume}
      p_devid: integer;            {device identifier (driver dependent)}
      p_uvid: vid;                 {volume id}
    { p_drvtemp: integer           {driver temp}
    { p_drvtemp2: shortint;        {second driver temp}
      p_letter: char;              {device specifier letter}
    { p_offline: boolean           {unit offline flag}
      p_uisinteractive: boolean;   {device echos input}
    { p_umediavalid: boolean;      {open files are valid}
    { p_uuppercase: boolean;       {volume name should be uppercased}
      p_uisfixed: boolean;         {medium not removable flag}
    { p_ureportchange: boolean;    {driver directive to report/ignore medium changes}
    { p_pad: 0..1                  {(not used)}
      p_uisblkd: boolean;          {blocked volume flag}
      p_umaxbytes: integer;        {volume size in bytes (unit)}
      p_disksize: integer  );      {volume size in bytes (disk)}

  var
    dam_proc:
      packed record case integer of
	0: (dam: damtype);
	1: (value, slink: integer);
      end;

    tm_proc:
      packed record case integer of
	0: (tm: amtype);
	1: (value, slink: integer);
      end;

    dam_ok: boolean;

    old_unit : unitentry;       {for "missing LIFDAM" bug fix. SFB}
		{This bug showed up when LIFDAM was not in INITLIB, but
		 HFSDAM was. If a superblock is on the disc, HFSDAM should
		 connect, but didn't, mainly because of the
		 'if (dam_proc.value <> 0)' test farther on.
		 We no longer do that test, but have to ensure the unit
		 doesn't get set up if the DAM is not available. SFB}

  procedure swap_temp_and_real_unit;
  var
     tmpunit: unitentry;
  begin
     tmpunit := unitable^[un];
     unitable^[un] := temp_unitable^[un];
     temp_unitable^[un] := tmpunit;
  end;

  begin {tea}
    if temp_unitable=nil then halt(-3); {unassigned pointer}

    { HFS only at beginning of disk (RAM units never tea'd) }
    if (dam_name = HFS_DAM_name) and (p_byteoffset <> 0) then
      dam_name := '';  {was LIF_DAM_name. Need value=0. SFB}

    dam_proc.value := value(dam_name);
    dam_proc.slink := 0;

    tm_proc.value := value(tm_name);
    tm_proc.slink := 0;

    old_unit := temp_unitable^[un]; {to restore later, if DAM not found. SFB}

    if
   { (dam_proc.value<>0) and           {removed. SFB}
     (tm_proc.value<>0) then  {assign the entry}
      begin

	with temp_unitable^[un] do
	  begin
	    dam             := dam_proc.dam;
	    tm              := tm_proc.tm;
	    sc              := p_sc;
	    ba              := p_ba;
	    du              := p_du;
	    dv              := p_dv;
	    byteoffset      := p_byteoffset;
	    devid           := p_devid;
	    uvid            := p_uvid;
	    dvrtemp         := 0;                 {always initially zero!}
	    dvrtemp2        := -1;                {always initially -1!}
	    letter          := p_letter;
	    offline         := false;             {always initially online!}
	    uisinteractive  := p_uisinteractive;
	    umediavalid     := false;             {never valid to start with}
	    uuppercase      := not p_uisblkd;     {assume case is significant}
	    uisfixed        := p_uisfixed;
	    ureportchange   := true;              {do report media changes}
	    pad             := 0;                 {not used}
	    uisblkd         := p_uisblkd;
	    if uisblkd then
	      umaxbytes     := p_umaxbytes;

	    if ( (tm_name = SCSIDSC_TM_name) and
		 ( (SCSIRemovableOption = AllAreHard) or
		   ( (SCSIRemovableOption = AllOver10MAreHard) and
		     (p_disksize >= hex('A00000'))
		   )
		 )
	       ) then
			pad := 1;
	  end; {with}


	if hfsbflg then
	  dam_ok := value(HFS_DAM_name)<>0      {SFB}
	else
	  if dam_proc.value <> 0 then           {SFB}
	    dam_ok := (dam_name=LIF_DAM_name) or (dam_name=SRM_DAM_name);

	with bootdev_MSUS, dav do {see if this entry points to it}
	  if (p_letter=letter) and  {wish we could use MSUSs_match function}
	     (p_sc=sc) and (p_ba=ba) and (p_du=du) and (p_dv=dv) and
	     dam_ok and
	     (p_byteoffset=0) then  {remember this unit number!}
	    bootdev_lun := un;

	if h_unitable <> nil then with h_unitable^ do begin
	  { temporarily swap temp and real unit entries }
	  swap_h_units(un);
	  swap_temp_and_real_unit;

	  if dam_name = HFS_DAM_name then
	    { force this unit to be HFS }
	    install_HFS(un, true)
	  else
	  if (p_byteoffset = 0)
	{ and (dam_name = LIF_DAM_name) {removed, as it blocks WS1.0, etc. SFB}
	  and (un >= first_harddisc_lun)
	  and (un <= last_harddisc_lun) then
	    { install HFS if disk has a superblock }
	    install_HFS(un, false);

	  if tbl[un].is_hfsunit then begin
	    { take up whole disk }
	    if p_disksize <> 0 then
	      unitable^[un].umaxbytes := p_disksize;
	    { prevent further units on this disk }
	    hfs_installed := true;
	  end;
	  swap_h_units(un);
	  swap_temp_and_real_unit;
	end;

      end; {if}

    {see if we found a dam for the unit. SFB}
    if temp_h_unitable <> NIL then
     with temp_h_unitable^ do   {was DAM found or HFS installed ?}
      begin
       if (not tbl[un].is_hfsunit) and (dam_proc.value=0) then
	temp_unitable^[un]:=old_unit  {if not, uninstall the entry. SFB}
      end
    else        {no possibility HFSDAM was installed}
     if dam_proc.value=0 then
      temp_unitable^[un]:=old_unit;   {if no dam, uninstall the entry. SFB}

  end; {tea}


function dam(ds: ds_type): string255;
  begin
    case ds of
$if thisversion = hfsversion$
      primary_dam:
	dam := LIF_DAM_name;
      secondary_dam:
	dam := HFS_DAM_name;
$end$
$if thisversion = ucsdversion$
      primary_dam:
	dam := LIF_DAM_name;
      secondary_dam:
	dam := UCSD_DAM_name;
$end$
      HFS_dam:
	dam := HFS_DAM_name;
      LIF_dam:
	dam := LIF_DAM_name;
      UCSD_dam:
	dam := UCSD_DAM_name;
    end; {case}
  end;
$page$

function medium_parameters(letter: char): mp_type;
  const {LOGICAL sizes unless otherwise noted}
    INTERNAL_mp = mp_type[tpm: 2* 33, bpt: 16*256];
    HP8290X_mp  = mp_type[tpm: 2* 33, bpt: 16*256];
    HP9885_mp   = mp_type[tpm: 1* 77, bpt: 30*256];  {physical size}
    HP9895_mp   = mp_type[tpm: 2* 77, bpt: 30*256];  {physical size}
    HP913X_A_mp = mp_type[tpm: 4*152, bpt: 31*256];
    HP913X_B_mp = mp_type[tpm: 4*305, bpt: 31*256];
    HP913X_C_mp = mp_type[tpm: 6*305, bpt: 31*256];
{INTERNAL ONLY BEGIN}
    HP7905_mp   = mp_type[tpm: 2*400, bpt: 48*256];  {fixed is half this size}
    HP7906_mp   = mp_type[tpm: 2*400, bpt: 48*256];  {fixed & remov same size}
    HP7920_mp   = mp_type[tpm: 5*800, bpt: 48*256];
    HP7925_mp   = mp_type[tpm: 9*800, bpt: 64*256];
{INTERNAL ONLY END}
    BUBBLE_mp   = mp_type[tpm: 1*512, bpt:  1*256];  {1 megabit unit}
   {BUBBLE_mp   = mp_type[tpm: 4*512, bpt:  1*256];} {4 megabit unit}
    null_mp     = mp_type[tpm:     0, bpt:      0];
  begin
    case letter of
      INTERNAL:  medium_parameters := INTERNAL_mp;
      HP8290X:   medium_parameters := HP8290X_mp;
      HP9885:    medium_parameters := HP9885_mp;
      HP9895:    medium_parameters := HP9895_mp;
      HP913X_A:  medium_parameters := HP913X_A_mp;
      HP913X_B:  medium_parameters := HP913X_B_mp;
      HP913X_C:  medium_parameters := HP913X_C_mp;
{INTERNAL ONLY BEGIN}
      HP7905:    medium_parameters := HP7905_mp;
      HP7906:    medium_parameters := HP7906_mp;
      HP7920:    medium_parameters := HP7920_mp;
      HP7925:    medium_parameters := HP7925_mp;
{INTERNAL ONLY END}
      BUBBLE:    medium_parameters := BUBBLE_mp;
      otherwise  medium_parameters := null_mp;
    end; {case}
  end;


function partitioning_parameters(letter: char): pp_type;
  const
    null_pp = pp_type[mvs: 0, mnv: 0];
  begin
    case letter of
      HP913X_A:  partitioning_parameters := HP913X_A_pp;
      HP913X_B:  partitioning_parameters := HP913X_B_pp;
      HP913X_C:  partitioning_parameters := HP913X_C_pp;
{INTERNAL ONLY BEGIN}
      HP7905:    partitioning_parameters := HP7905_pp;
      HP7906:    partitioning_parameters := HP7906_pp;
      HP7920:    partitioning_parameters := HP7920_pp;
      HP7925:    partitioning_parameters := HP7925_pp;
{INTERNAL ONLY END}
      CS80:      partitioning_parameters := CS80disc_pp;
      SCSI:      partitioning_parameters := SCSIdisc_pp;        {DEW 09/89 - added SCSI support}
      otherwise  partitioning_parameters := null_pp;
    end; {case}
  end;
$page$

function number_vols(mp: mp_type; pp: pp_type): shortint;
  var
    nvols: shortint;
  begin
    if pp.mnv<0 then  {negative implies autovolume feature; use absolute value}
      pp.mnv := -pp.mnv;
    if pp.mvs<=0 then pp.mvs := 1;  {guard against div's by 0}
    if mp.bpt<=0 then mp.bpt := 1;  {guard against div's by 0}
    nvols := mp.tpm div ((pp.mvs+mp.bpt-1) div mp.bpt);
    if (nvols=0) and (mp.tpm>0) then
      nvols := 1;  {physical vol smaller than the specified minimum vol size}
    if nvols>pp.mnv then  {cut back, even to zero if specified}
      nvols := pp.mnv;
    number_vols := nvols;
  end;


function svol_bytes(letter: char): integer;
  var
    mp: mp_type;
  begin
    mp := medium_parameters(letter);
    svol_bytes := mp.bpt*mp.tpm;  {single volume bytes}
  end;


function vol_bytes(current_vol, number_vols: shortint; mp: mp_type): integer;
  var
    tracks: integer;
  begin
    tracks := mp.tpm div number_vols;           {each vol gets this much}
    if current_vol=number_vols-1 then
      tracks := tracks+mp.tpm mod number_vols;  {last vol gets any extra}
    vol_bytes := tracks*mp.bpt;
  end;


function vol_offset(current_vol, number_vols: shortint; mp: mp_type): integer;
  begin
    vol_offset := (mp.tpm div number_vols)*current_vol*mp.bpt;
  end;


function block_boundaries(mp: mp_type): mp_type;
  begin
    block_boundaries.tpm := mp.tpm*mp.bpt div 512;
    block_boundaries.bpt := 512;
  end;
$page$

{ standard driver-oriented table entry assignment procedures }


procedure tea_nounit(un:unitnum);
  begin
    tea(un,NO_DAM_name,NULL_TM_name,0,0,0,0,0,0,'',#0,F,F,F,0,0);
  end;


procedure tea_memory_volume_dam(ds:ds_type);
  begin
    tea(0,dam(ds),NULL_TM_name,0,0,0,0,0,0,'',RAM,F,T,T,0,0);
  end;


procedure tea_crt(un:unitnum);
  begin
    tea(un,UNBLOCKED_DAM_name,CRT_TM_name,0,0,0,0,0,0,'CONSOLE',#0,T,T,F,0,0);
  end;


procedure tea_kbd(un:unitnum);
  begin
    tea(un,UNBLOCKED_DAM_name,KBD_TM_name,0,0,0,0,0,0,'SYSTERM',#0,F,T,F,0,0);
  end;


procedure tea_mini(un:unitnum;ds:ds_type;du:shortint);
  begin
    check(du, 0, 1);
    tea(un,dam(ds),MINI_TM_name,0,0,du,0,0,0,'',INTERNAL,
			      F,F,T,svol_bytes(INTERNAL),0);
  end;


procedure tea_boot(un: unitnum);
  begin
    tea(un,BOOT_DAM_name,BOOT_TM_name,0,0,0,0,0,0,'',#0,F,F,T,maxint,0);
  end;


procedure tea_srm(un:unitnum;sc,{node}ba,{unit}du:shortint);
  begin
    check(sc, 7, 31);
    check(ba, 0, 127);
    if du<>0 then check(du, 7, 26);
    tea(un,SRM_DAM_name,SRM_TM_name,sc,ba,du,0,0,0,'',SRM,F,T,T,maxint,0);
  end;


procedure tea_local_printer(un:unitnum;sc,ba:shortint;uvid:vid;bto:integer);
  begin
    check(sc, 7, 31);
    check(ba, 0, 30);
    check(bto, 0, 60*60*1000);  {one hour should be enough!}
    tea(un,UNBLOCKED_DAM_name,PRINTER_TM_name,sc,ba,0,0,0,bto,uvid,#0,
							    F,T,F,0,0);
  end;
$page$

procedure tea_HP9885(un:unitnum;ds:ds_type;sc,du,block_os:shortint);
  var
    os: integer;
  begin
    check(sc, 8, 31);
    check(du, 0, 3);
    os := block_os*512;
    check(os, 0, svol_bytes(HP9885)-1);
    tea(un,dam(ds),F9885_TM_name,sc,0,du,0,os,0,'',HP9885,
			    F,F,T,svol_bytes(HP9885)-os,0);
  end;


procedure tea_HP9895(un:unitnum;ds:ds_type;sc,ba,du,block_os:shortint);
  var
    os: integer;
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 3);
    os := block_os*512;
    check(os, 0, svol_bytes(HP9895)-1);
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,0,os,0,'',HP9895,
			       F,F,T,svol_bytes(HP9895)-os,0);
  end;


procedure tea_HP8290X(un:unitnum;ds:ds_type;sc,ba,du:shortint);
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 3);
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,0,0,0,'',HP8290X,
				  F,F,T,svol_bytes(HP8290X),0);
  end;


procedure tea_amigo_sv(un:unitnum;ds:ds_type;sc,ba,du:shortint;os:integer;lr:char;mb:integer);
  var
    medium_size: integer;
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 7);
{INTERNAL ONLY BEGIN}
    if not (lr in [HP913X_A, HP913X_B, HP913X_C, HP7920, HP7925]) then
{EXTERNAL VERSION
    if not (lr in [HP913X_A, HP913X_B, HP913X_C]) then
{INTERNAL ONLY END}
      halt(-8); {value range error}
    medium_size := svol_bytes(lr);
    check(os, 0, medium_size-1);
    if os mod 256<>0 then halt(-8) {value range error};
    check(mb, 1, medium_size-os);
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,0,os,0,'',lr,F,T,T,mb,medium_size);
  end;
$page$

{INTERNAL ONLY BEGIN}
procedure tea_amigo_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;os:integer;lr:char;mb:integer);
  var
    medium_size: integer;
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 7);
    check(dv, 0, 1);
    if not (lr in [HP7905, HP7906]) then halt(-8);  {value range error}
    medium_size := svol_bytes(lr);
    if (lr=HP7905) and (dv<>0) then
      medium_size := medium_size div 2;  {7905 fixed is half as big!}
    check(os, 0, medium_size-1);
    if os mod 256<>0 then halt(-8) {value range error};
    check(mb, 1, medium_size-os);
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,dv,os,0,'',lr,F,T,T,mb,medium_size);
  end;
{INTERNAL ONLY END}
$page$

procedure tea_CS80_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;os,id,
						   mb,disksize:integer);
  {
    CS80 multiple (logical) volume assignment procedure:
    1) devid must match the actual HP product number as found in describe
    2) offset and umaxbytes are fixed
    3) the uisfixed field is assigned by the driver in the clearunit procedure
  }
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 14);
    check(dv, 0, 7);
    tea(un,dam(ds),CS80_TM_name,sc,ba,du,dv,os,id,'',CS80,F,F,T,mb,disksize);
  end;


procedure tea_CS80_sv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint);
  {
    CS80 single (logical) volume assignment procedure:
    1) byteoffset always assumed to be zero
    2) umaxbytes is dependent upon the media loaded, thus it is set by the
       driver at clearunit time and whenever it detects a media change.
       BOTTOM LINE: the medium CANNOT be partitioned into multiple volumes!
    3) the uisfixed field is assigned by the driver in the clearunit procedure
    4) device can either be a disc (presumably a floppy) or a tape
  }
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 14);
    check(dv, 0, 7);
    tea(un,dam(ds),CS80_TM_name,sc,ba,du,dv,0,-1,'',CS80,F,F,T,0,0);
  end;


procedure tea_SCSI_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;os,id,
						   mb,disksize:integer);
  {
    09/89 DEW - added SCSI support
    SCSI multiple (logical) volume assignment procedure:
    1) devid must match the actual HP product number as found in describe
    2) offset and umaxbytes are fixed
    3) the uisfixed field is assigned by the driver in the clearunit procedure
  }
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 255);
    check(dv, 0, 0);   {SCSI Secondary Units not supported}
    tea(un,dam(ds),SCSIDSC_TM_name,sc,ba,du,dv,os,id,'',SCSI,F,F,T,mb,disksize);
  end;


procedure tea_SCSI_sv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint);
  {
    09/89 DEW - added SCSI support
    SCSI single (logical) volume assignment procedure:
    1) byteoffset always assumed to be zero
    2) umaxbytes is dependent upon the media loaded, thus it is set by the
       driver at clearunit time and whenever it detects a media change.
       BOTTOM LINE: the medium CANNOT be partitioned into multiple volumes!
    3) the uisfixed field is assigned by the driver in the clearunit procedure
    4) device can either be a disc (presumably a floppy) or a tape
  }
  begin
    check(sc, 7, 31);
    check(ba, 0, 7);
    check(du, 0, 255);
    check(dv, 0, 0);   {SCSI Secondary Units not supported}
    tea(un,dam(ds),SCSIDSC_TM_name,sc,ba,du,dv,0,-1,'',SCSI,F,F,T,0,0);
  end;


procedure tea_flpy(un:unitnum;lr:char;ds:ds_type;sc,ba,du:shortint);
  begin
    case lr of
      INTERNAL: tea_mini(un,ds,du);
      HP8290X:  tea_HP8290X(un,ds,sc,ba,du);
      CS80:     tea_CS80_sv(un,ds,sc,ba,du,0);
      SCSI:     tea_SCSI_sv(un,ds,sc,ba,du,0);  {DEW 09/89 - added SCSI support}
      HP9885:   tea_HP9885(un,ds,sc,du,0);
      HP9895:   tea_HP9895(un,ds,sc,ba,du,0);
      otherwise halt(-8) {value range error}
    end;  {case}
  end;

$page$

procedure tea_BUBBLE(un:unitnum;ds:ds_type;sc:shortint);
  begin
    { NOTE THAT UMAXBYTES IS ASSIGNED AT CLEARUNIT TIME }
    check(sc,7,31);
    tea(un,dam(ds),BUBBLE_TM_name,sc,0,0,0,0,0,'',BUBBLE,F,T,T,0,0);
  end;

procedure tea_EPROM(un:unitnum;ds:ds_type;sn:shortint);
  begin
    { NOTE THAT UMAXBYTES IS ASSIGNED AT CLEARUNIT TIME }
    check(sn,0,MAXUNIT);
    tea(un,dam(ds),EPROM_TM_name,0,0,0,sn,0,0,'',EPROM,F,T,T,0,0);
  end;

$page$

procedure create_temp_unitable;
  var
    lunit: unitnum;
  begin
    new(temp_unitable);
    tea_nounit(0);  {assign one dummy entry}
    for lunit := 1 to maxunit do  {copy others; avoid symbol table search each time!}
      temp_unitable^[lunit] := temp_unitable^[0];
    if h_unitable <> nil then begin
      new(temp_h_unitable);
      temp_h_unitable^ := h_unitable^;
      call(h_unitable^.init_cache_proc);
      for lunit := 0 to maxunit do
	swap_h_units(lunit);
      { now h_unitable is as before, temp_h_unitable is initialized }
    end;
  end;


procedure assign_and_clear_unit(lunit: unitnum);
  var
    f: fib;
  begin
    if temp_unitable=nil then halt(-3); {unassigned pointer}
    with unitable^[lunit], f do
      if (letter<>RAM) or (lunit=0) then
	begin
	  unitable^[lunit] := temp_unitable^[lunit];
	  funit := lunit;
	  delay_timer(1000); { Fix for SRM coax configuration }
	  if h_unitable <> nil then
	    h_unitable^.tbl[lunit] := temp_h_unitable^.tbl[lunit];
	  call(tm, addr(f), clearunit, lunit, 0, 0);
	  offline := uisblkd and (ioresult<>0);
	end
	else
	  { try to convert old RAM volumes to HFS }
	  install_HFS(lunit, false);
  end;

{----------------------------------------------------------------------}
{
{ set the base_unum fields in h_unitable
{ base_unum is the unit number of the LOWEST unit on this disk
{ e.g., if #11 and #12 share a disk, base_unum for both is 11.
}
procedure set_base_unums;
var
    i,j: unitnum;
begin
    if h_unitable <> nil then with h_unitable^ do
	for i := 1 to maxunit do
	    for j := i+1 to maxunit do
		{ HFS? }
		if tbl[j].is_hfsunit
		{ higher number not yet assigned? }
		and (tbl[j].base_unum = j)
		{ share disk? }
		and on_same_medium(i, j) then
		    tbl[j].base_unum := i;
end;

procedure assign_temp_unitable;
  var
    lunit: unitnum;
    i: integer;
  begin
    if temp_unitable=nil then halt(-3);  {unassigned pointer}
    lockfiles;  {close all standard system files}
    for lunit := 0 to maxunit do
      assign_and_clear_unit(lunit);
    set_base_unums;
    { configure HFS cache }
    if h_unitable <> nil then begin
      call(h_unitable^.config_cache_proc);
    end;

  end;


function sysunit_ok(system_unit: unitnum): boolean;
  begin
    sysunit := system_unit;
    initsysunit;
    with unitable^[system_unit] do
      sysunit_ok := uisblkd and not offline and (uvid<>'');
  end;


procedure zap_assigned_unit(lunit: unitnum);
  begin
    tea_nounit(lunit);  {zap the temp unitable entry}
    unitable^[lunit] := temp_unitable^[lunit];  {now zap the real one!}
  end;
$page$

function on_same_medium(lun1, lun2: unitnum): boolean;
  var
    uep: ^unitentry;
  begin {on_same_medium}
    uep := addr(unitable^[lun2]);
    with unitable^[lun1] do
      on_same_medium := (sc=uep^.sc) and (ba=uep^.ba) and
			(du=uep^.du) and (dv=uep^.dv) and
			(letter=uep^.letter) and (letter<>'R');
  end; {on_same_medium}


procedure remove_extraneous_volumes(first_lun, last_lun: unitnum);
  var
    first_lun_ok: boolean;
    lun: unitnum;
  begin {remove_extraneous_volumes}
    first_lun_ok := false;
    while first_lun<last_lun do
      if first_lun_ok then
	begin
	  lun := first_lun+1;
	  with unitable^[first_lun] do
	    while (lun<=last_lun) and not sysunit_ok(lun) do
	      begin
		if unitable^[lun].byteoffset = byteoffset+umaxbytes then
		  begin
		    umaxbytes := umaxbytes+unitable^[lun].umaxbytes;
		    zap_assigned_unit(lun);
		  end;
		lun := lun+1;
	      end;  {while}
	  first_lun := lun;
	end {then}
      else if sysunit_ok(first_lun) then
	first_lun_ok := true
      else
	first_lun := first_lun+1;
  end; {remove_extraneous_volumes}

end; {ctr}
$page$

module BRstuff;  {BOOTROM stuff}

  (********************************************)
  (*                                          *)
  (*               Warning:                   *)
  (*   This module should not be modified!    *)
  (*                                          *)
  (********************************************)

import
  sysglobals, options, ctr;

export
  const
    INTERNAL_MSUS = MSUS_type
      [ flpy_flags: assign_neither_flpy_unit, letter: INTERNAL,
	dav: dav_type[sc: -1, ba: -1, du:  0, dv: -1] ];

  function internal_mini_present: boolean;
  procedure get_bootdevice_MSUS(var MSUS: MSUS_type);

implement {BRstuff}

type
  signed4     = -8..7;
  signed8     = -128..127;

  fmt_type =  {format field in the msus byte}
    (f0,f1,f2,f3,f4,f5,f6,f7);

  dev_type =  {device field in the msus byte}
    ( d0, d1, d2, d3, d4, d5, d6, d7, d8, d9,d10,d11,d12,d13,d14,d15,
     d16,d17,d18,d19,d20,d21,d22,d23,d24,d25,d26,d27,d28,d29,d30,d31);

  BR_msus_type = {BOOTROM's mass storage unit specifier}
    packed record case boolean of
      false:  {8-bit unit number}
	( fmt: fmt_type;  {directory format}
	  dev: dev_type;  {device}
	  un: signed8;    {8-bit unit number}
	  sc: signed8;    {select code}
	  ba: signed8     {bus address}  );
      true:  {4-bit volume / 4-bit unit number for CS80 & 7905/06 discs}
	( pad: signed8;   {format/device byte}
	  vn4: signed4;   {4-bit volume number}
	  un4: signed4;   {4-bit unit number}  );
    end; {BR_msus_type}

var
  ROM_ID[16382]:  {BOOTROM identification word}
    shortint;

  ndrives[-296]:  {Maximum Unit for Internal Mini-Floppy}
    packed record  b: signed8;  end;

  default_msus[-292]:  {boot device's msus}
    BR_msus_type;
$page$

function internal_mini_present: boolean;
  begin
    if ROM_ID<0
      then internal_mini_present := true            {1.0 BOOTROM on 9826}
      else internal_mini_present := ndrives.b<>-1;  {2.0 or greater BOOTROM}
  end;


procedure get_bootdevice_MSUS(var MSUS: MSUS_type);
  type
    letter_table_type = array[dev_type] of char;
  const
    letter_table =  {BOOTROM dev to Pascal letter conversion table}
      letter_table_type
	[ INTERNAL, NODEVICE, NODEVICE, NODEVICE, HP9895,   HP8290X,  HP9885,   HP913X_A,
{INTERNAL ONLY BEGIN}
	  HP913X_B, HP913X_C, HP7905,   HP7906,   HP7920,   HP7925,   SCSI,     NODEVICE, {DEW - added SCSI}
{EXTERNAL VERSION
	  HP913X_B, HP913X_C, NODEVICE, NODEVICE, NODEVICE, NODEVICE, SCSI,     NODEVICE, {DEW - added SCSI}
{INTERNAL ONLY END}
	  CS80,     CS80,     NODEVICE, NODEVICE, NODEVICE, NODEVICE, BUBBLE  , NODEVICE,
	  NODEVICE, NODEVICE, NODEVICE, NODEVICE, NODEVICE, NODEVICE, NODEVICE, NODEVICE  ];
  begin
    if ROM_ID<0 then  {1.0 Boot ROM on 9826; internal minifloppy only}
      MSUS := INTERNAL_MSUS
    else  {2.0 or greater Boot ROM}
      with default_msus do
	begin
	  if fmt=f7 then  {non sector-oriented device}
	    if (dev=d1) OR (dev=d2)    {added dev=d2 to allow LANSRM. DEW/RDQ/SFB - 5/5/89}
	      then MSUS.letter := SRM
	      else MSUS.letter := NODEVICE
	  else  {sector-oriented device}
	    MSUS.letter := letter_table[dev];
	  MSUS.dav.sc := sc;
	  MSUS.dav.ba := ba;
{INTERNAL ONLY BEGIN}
	  if MSUS.letter in [HP7905, HP7906, CS80, SCSI] then   {DEW 09/89 - added SCSI support}
{EXTERNAL VERSION
	  if MSUS.letter in [CS80, SCSI] then                   {DEW 09/89 - added SCSI support}
{INTERNAL ONLY END}
	    begin
	      MSUS.dav.du := un4;
	      MSUS.dav.dv := vn4;
	    end  {then}
	  else
	    begin
	      MSUS.dav.du := un;
	      MSUS.dav.dv := 0;
	    end;  {else}
	end; {with}
  end;

end; {BRstuff}
$page$

module scanstuff;

  (********************************************)
  (*                                          *)
  (*               Warning:                   *)
  (*   This module should not be modified!    *)
  (*                                          *)
  (********************************************)

import
  sysglobals, options, ctr;

export

  procedure init_scanstuff;
  function scanneddevice_letter(scan_dav: dav_type): char;
  procedure get_CS80_parms(CS80dav: dav_type;
			   var CS80dt: byte; var CS80id: integer;
			   var CS80hardvols: shortint; var CS80mp: mp_type);

implement {scanstuff}


type
  uep_type = ^unitentry;

  uep_proc_type = procedure(uep: uep_type);
  HPIBget_amigo_ident_type = procedure(uep: uep_type; var ident: shortint);
  get_letter_type = procedure(uep: uep_type; ident: shortint; var letter: char);
  get_CS80_parms_type = procedure(var CS80dt: byte;
				  var CS80id: integer;
				  var CS80hardvols: shortint;
				  var CS80mp: mp_type);

  proc_type =
    packed record case integer of
      0: (value, slink: integer);
      1: (up: uep_proc_type);
      2: (gai: HPIBget_amigo_ident_type);
      3: (gl: get_letter_type);
      4: (gcp: get_CS80_parms_type);
    end;


var
  allocate_bkgnd_info_proc: proc_type;
  deallocate_bkgnd_info_proc: proc_type;
  abort_bkgnd_process_proc: proc_type;
  HPIBcheck_sc_proc: proc_type;
  HPIBget_amigo_ident_proc: proc_type;

  get_amigo_letter_proc: proc_type;
  get_CS80_letter_proc: proc_type;
  get_CS80_parms_proc: proc_type;

  bkgnd_and_dischpib_present: boolean;
$page$

function scanneddevice_letter(scan_dav: dav_type): char;

  type
    amigo_class_type = {upper three bits of the first ident byte}
      (storage, display, data_communication, processor,
       stimulus, mesasurement, unassigned6, unassigned7);

  var
    ue: unitentry;
    ident:
      packed record case integer of
	0: (word: shortint);
	1: (upper_byte, lower_byte: byte);
	2: (amigo_class: amigo_class_type);
      end;

  procedure set_scanneddevice_letter(get_letter_proc: proc_type);
    var
      device_letter: char;
    begin {set_scanneddevice_letter}
      if get_letter_proc.value<>0 then
	begin
	  call(get_letter_proc.gl, addr(ue), ident.word, device_letter);
	  scanneddevice_letter := device_letter;
	end; {if}
    end; {set_scanneddevice_letter}

  begin {scanneddevice_letter}
    scanneddevice_letter := NODEVICE;  {until proven otherwise}
    if bkgnd_and_dischpib_present then
      try
	ue.sc := scan_dav.sc;
	ue.ba := scan_dav.ba;
	ue.du := scan_dav.du;
	ue.dv := scan_dav.dv;
	call(allocate_bkgnd_info_proc.up, addr(ue));
	call(HPIBcheck_sc_proc.up, addr(ue));
	call(HPIBget_amigo_ident_proc.gai, addr(ue), ident.word);
	if ident.amigo_class=storage then
	    if ident.upper_byte=2
	      then set_scanneddevice_letter(get_CS80_letter_proc)
	      else set_scanneddevice_letter(get_amigo_letter_proc)
	else if ident.amigo_class=display then
	    scanneddevice_letter := PRINTER;
	call(deallocate_bkgnd_info_proc.up, addr(ue));
      recover
	call(abort_bkgnd_process_proc.up, addr(ue));
  end; {scanneddevice_letter}
$page$

procedure get_CS80_parms(CS80dav: dav_type;
			 var CS80dt: byte; var CS80id: integer;
			 var CS80hardvols: shortint; var CS80mp: mp_type);
  begin {get_CS80_parms}
    if (scanneddevice_letter(CS80dav)=CS80) and (get_CS80_parms_proc.value<>0) then
      call(get_CS80_parms_proc.gcp, CS80dt, CS80id, CS80hardvols, CS80mp)
    else
      begin
	CS80dt := 255;
	CS80id := 0;
	CS80hardvols := 0;
	CS80mp := medium_parameters(NODEVICE);
      end; {else}
  end; {get_CS80_parms}


procedure init_scanstuff;
  {
    NOTE: all procedure variables are GLOBAL, so their static links are
	  guaranteed to have been cleared @@ load time
  }
  begin {init_scanstuff}
    allocate_bkgnd_info_proc.value   := value('BKGND_ALLOCATE_BKGND_INFO');
    deallocate_bkgnd_info_proc.value := value('BKGND_DEALLOCATE_BKGND_INFO');
    abort_bkgnd_process_proc.value   := value('BKGND_ABORT_BKGND_PROCESS');
    HPIBcheck_sc_proc.value          := value('DISCHPIB_HPIBCHECK_SC');
    HPIBget_amigo_ident_proc.value   := value('DISCHPIB_HPIBGET_AMIGO_IDENT');

    get_amigo_letter_proc.value      := value('AMIGODVR_GET_LETTER');
    get_CS80_letter_proc.value       := value('CS80DVR_GET_LETTER');
    get_CS80_parms_proc.value        := value('CS80DVR_GET_PARMS');

    bkgnd_and_dischpib_present := (allocate_bkgnd_info_proc.value<>0) and
				  (deallocate_bkgnd_info_proc.value<>0) and
				  (abort_bkgnd_process_proc.value<>0) and
				  (HPIBcheck_sc_proc.value<>0) and
				  (HPIBget_amigo_ident_proc.value<>0);
  end; {init_scanstuff}


end; {scanstuff}
$page$

module SCSIscanstuff;           {DEW 09/89 - added SCSI support}

  (********************************************)
  (*                                          *)
  (*               Warning:                   *)
  (*   This module should not be modified!    *)
  (*                                          *)
  (********************************************)


import sysglobals, asm, options, ctr;

export
	procedure init_SCSIscanstuff;
	function SCSIscanneddevice_letter(scan_dav: dav_type): char;
	procedure get_SCSI_parms(    SCSIdav:dav_type;
				 var SCSIdt:byte;
				 var SCSIRemovable:boolean;
				 var SCSImp:mp_type);


implement

type
	uep_type = ^unitentry;

	IsScsiCardType          = procedure(    sc:byte;
					    var yes:boolean);
	ScsiSBSizeType          = procedure(var size:integer);
	ScsiSBInitType          = procedure(    pSB:ANYPTR;  pUP:uep_type);
	ScsiCheckDevType        = procedure(    pSB:ANYPTR);
	ScsiDevInfoType         = procedure(    pSB:ANYPTR;
					    var DevType, AnsiVersion:integer;
					    var Removable:boolean;
					    var VendorString:String255);
	ScsiDiscSizeType        = procedure(    pSB:ANYPTR;
					    var NumBytesBlock, NumBlocksTrack,
						NumTracksCylinder, NumCylinders:integer);
	ScsiPreventType         = procedure(    pSB:ANYPTR);

	ScsiProcType            = packed record case integer of
						0:(value, slink:integer);
						1:(IsCard:IsScsiCardType);
						2:(SBSize:ScsiSBSizeType);
						3:(SBInit:ScsiSBInitType);
						4:(CheckDev:ScsiCheckDevType);
						5:(DevInfo:ScsiDevInfoType);
						6:(DiscSize:ScsiDiscSizeType);
						7:(Prevent:ScsiPreventType);
				  end;

var
	IsScsiCardProc,
	ScsiSBSizeProc,
	ScsiSBInitProc,
	ScsiCheckDevProc,
	ScsiDevInfoProc,
	ScsiDiscSizeProc,
	ScsiPreventProc:ScsiProcType;

	pSB:ANYPTR;
	pUnit:uep_type;
	SCSILIBinMemory:boolean;


procedure init_SCSIscanstuff;
var
	i:integer;
begin
	IsScsiCardProc.value            := value('SCSILIB_ISSCSICARD');
	ScsiSBSizeProc.value            := value('SCSILIB_SCSISBSIZE');
	ScsiSBInitProc.value            := value('SCSILIB_SCSISBINIT');
	ScsiCheckDevProc.value          := value('SCSILIB_SCSICHECKDEV');
	ScsiDevInfoProc.value           := value('SCSILIB_SCSIDEVINFO');
	ScsiDiscSizeProc.value          := value('SCSILIB_SCSIDISCSIZE');
	ScsiPreventProc.value           := value('SCSILIB_SCSIDISCPREVENT');

	SCSILIBinMemory :=      (IsScsiCardProc.value <> 0) and
				(ScsiSBSizeProc.value <> 0) and
				(ScsiSBInitProc.value <> 0) and
				(ScsiCheckDevProc.value <> 0) and
				(ScsiDevInfoProc.value <> 0) and
				(ScsiDiscSizeProc.value <> 0) and
				(ScsiPreventProc.value <> 0);

	if SCSILIBinMemory then
	begin
		call(ScsiSBSizeProc.SBSize, i);
		newbytes(pSB, i);
		newbytes(pUnit, sizeof(unitentry));
	end;
end;

procedure SetUnit(pUnit:uep_type; dav:dav_type);
begin
	with pUnit^ do
	begin
		sc := dav.sc;
		ba := dav.ba;
		du := dav.du;
		dv := dav.dv;
	end;
end;

function SCSIscanneddevice_letter(scan_dav: dav_type): char;
var
	b:boolean;
begin
	SCSIscanneddevice_letter := NODEVICE;  {until proven otherwise}
	if SCSILIBinMemory then
	begin
		call(IsScsiCardProc.IsCard, scan_dav.sc, b);
		if b then {this is a scsi card}
		begin
			SetUnit(pUnit, scan_dav);
			call(ScsiSBInitProc.SBInit, pSB, addr(scan_dav));
			call(ScsiCheckDevProc.CheckDev, pSB);
			if (ioresult = ord(inoerror)) or
			   (ioresult = ord(zmediumchanged)) or
			   (ioresult = ord(znotready)) then
				SCSIscanneddevice_letter := SCSI;
			ioresult := ord(inoerror);
		end;
	end;
end;


procedure get_SCSI_parms(    SCSIdav:dav_type;
			 var SCSIdt:byte;
			 var SCSIRemovable:boolean;
			 var SCSImp:mp_type);
label   1;
var
	dt, ansi:integer;
	s:string255;
	nbps, nspt, ntpc, nc:integer;
	DoPrevent:boolean;
begin
	DoPrevent := FALSE;
	if SCSIscanneddevice_letter(SCSIdav) = SCSI then
	begin
		call(ScsiDevInfoProc.DevInfo, pSB, dt, ansi, SCSIRemovable, s);
		if (ioresult <> ord(inoerror)) or (dt <> 0) then
			{error on communication or not a disk type}
			goto 1;
		SCSIdt := dt;
		if (SCSIRemovable) and (SCSIRemovableOption = AllAreHard) then
		begin
			SCSIRemovable := FALSE;
			DoPrevent := TRUE;
		end;
		call(ScsiDiscSizeProc.DiscSize, pSB, nbps, nspt, ntpc, nc);
		if ioresult = ord(inoerror) then
		begin
			SCSImp.tpm := ntpc * nc;
			SCSImp.bpt := nbps * nspt;
			if (SCSIRemovable) and
			   (SCSIRemovableOption = AllOver10MAreHard) and
			   ( (SCSImp.tpm * SCSImp.bpt) >= hex('A00000') ) then
			begin
				SCSIRemovable := FALSE;
				DoPrevent := TRUE;
			end;
		end
		else if SCSIRemovable then
		begin
			ioresult := ord(inoerror);
			SCSImp.tpm := 1;
			SCSImp.bpt := 256;
		end
		else
			goto 1;
	end
	else
	begin
		1:
		ioresult := ord(inoerror);
		DoPrevent := FALSE;
		SCSIdt := 255;
		SCSImp.tpm := 0;
		SCSImp.bpt := 0;
	end;

	if (DoPrevent) then
	begin
		call(ScsiPreventProc.Prevent, pSB);
		ioresult := ord(inoerror);
	end;
end;



end; {SCSIscanstuff}
$page$

{program ctable}

  (********************************************)
  (*               Caution:                   *)
  (* Modify this section only if the desired  *)
  (* configuration cannot be achieved by      *)
  (* modifying the OPTIONS module.            *)
  (********************************************)

import
  sysglobals, fs, ldr, options, ctr, BRstuff, scanstuff, SCSIscanstuff, bootDAMmodule;  {DEW - added SCSI}

const
  sysprefix = '/WORKSTATIONS/SYSTEM';
  null_dav =
    dav_type[sc: -1, ba: -1, du: -1, dv: -1];
  null_MSUS =
    MSUS_type[flpy_flags: assign_neither_flpy_unit, letter: NODEVICE, dav: null_dav];
  HP9885_default_MSUS =
    MSUS_type[flpy_flags: assign_neither_flpy_unit, letter: HP9885, dav: HP9885_default_dav];
  MSUS_array_size = 10;

type
  MSUS_array_type = array [1..MSUS_array_size] of MSUS_type;
  log_MSUS_options = (search_for_other_units, do_not_search_for_other_units);

var
  flpy_MSUS: MSUS_array_type;
  harddisc_MSUS: MSUS_array_type;
  CS80tape_MSUS: MSUS_array_type;
  scanner_MSUS: MSUS_type;

  local_printer_dav: dav_type;
  SRM_dav: dav_type;
  BUBBLE_dav: dav_type;

  index, select_code, bus_address, i, nvols: shortint; {LAF 870622}
  lun, lun1, lun2: unitnum;
  CS80dt: byte;
  CS80id: integer;
  CS80hardvols: shortint;
  SCSIdt: byte;
  SCSIRemovable:boolean;
  mp: mp_type;
  pp: pp_type;
  ok: boolean;



function increment_and_test_lun: boolean;
  begin {increment_and_test_lun}
    lun := lun+1;
    increment_and_test_lun := lun<=last_harddisc_lun;
  end; {increment_and_test_lun}
$page$

function unit_prefix_successful(dirname: fid): boolean;
  var
    unitnum: integer;
    kvid: vid;
  begin {unit_prefix_successful}
    doprefix(dirname, kvid, unitnum, true);
    unit_prefix_successful := ioresult=ord(inoerror);
  end; {unit_prefix_successful}


procedure zero_out_NA_fields(var device_MSUS: MSUS_type);
  const
    clear = true;
    retain = false;
  procedure zero_fields(sc, ba, du, dv: boolean);
    begin  {zero_fields}
      if sc then device_MSUS.dav.sc := 0;
      if ba then device_MSUS.dav.ba := 0;
      if du then device_MSUS.dav.du := 0;
      if dv then device_MSUS.dav.dv := 0;
    end;  {zero_fields}
  begin {zero_out_NA_fields}
    case device_MSUS.letter of
      INTERNAL:
	zero_fields({sc} clear , {ba} clear , {du} retain, {dv} clear );
      HP9885:
	zero_fields({sc} retain, {ba} clear , {du} retain, {dv} clear );
{INTERNAL ONLY BEGIN}
      HP9895, HP8290X, HP913X_A, HP913X_B, HP913X_C, HP7920, HP7925, SRM:
{EXTERNAL VERSION
      HP9895, HP8290X, HP913X_A, HP913X_B, HP913X_C, SRM:
{INTERNAL ONLY END}
	zero_fields({sc} retain, {ba} retain, {du} retain, {dv} clear );
      BUBBLE:
	zero_fields({sc} retain, {ba} clear , {du} clear , {dv} clear );
      EPROM:
	zero_fields({sc} clear , {ba} clear , {du} clear , {dv} retain);
      otherwise  {includes HP7905, HP7906, CS80, SCSI}
	{do nothing};
    end; {case}
  end; {zero_out_NA_fields}


procedure assign_flpy_unit_pair(lun: unitnum; dam: ds_type; index: shortint);
  begin {assign_flpy_unit_pair}
    with flpy_MSUS[index], flpy_flags, dav do
      begin
	if assign_even_unit then
	  begin
	    tea_flpy(lun, letter, dam, sc, ba, du);
	    lun := lun+1;
	  end; {if}
	if assign_odd_unit then
	  tea_flpy(lun, letter, dam, sc, ba, du+1);
      end; {with}
  end; {assign_flpy_unit_pair}
$page$

procedure log_MSUS(MSUS: MSUS_type; log_MSUS_option: log_MSUS_options);


  type
    log_flpy_MSUS_options = (assign_both_units, assign_only_this_unit);


  procedure log_specific_MSUS(var specific_MSUS: MSUS_array_type);
    var
      index: shortint;
      found: boolean;
    begin {log_specific_MSUS}
      index := 0;
      repeat
	index := index+1;
	found := MSUSs_match(specific_MSUS[index], MSUS);
      until found or (index=MSUS_array_size);
      if found
	then MSUS.flpy_flags := specific_MSUS[index].flpy_flags {preserve}
	else MSUS.flpy_flags := assign_neither_flpy_unit;       {initialize}
      while index>1 do
	begin
	  specific_MSUS[index] := specific_MSUS[index-1];
	  index := index-1;
	end;  {while}
      specific_MSUS[1] := MSUS;
    end; {log_specific_MSUS}


  procedure log_flpy_MSUS(log_flpy_MSUS_option: log_flpy_MSUS_options);
    var
      odd_unit: boolean;
    begin {log_flpy_MSUS}
      with MSUS.dav do
	begin  {since floppy units are assigned in pairs...}
	  odd_unit := odd(du);     {remember which unit this actually is...}
	  du := du-ord(odd_unit);  {but log only the even-numbered unit!}
	end; {with}
      log_specific_MSUS(flpy_MSUS);
      with flpy_MSUS[1] do  {update the flpy_flags}
	if log_flpy_MSUS_option=assign_both_units then
	  flpy_flags := assign_both_flpy_units
	else  {set only this unit's assignment flag}
	  if odd_unit
	    then flpy_flags.assign_odd_unit  := true
	    else flpy_flags.assign_even_unit := true;
    end; {log_flpy_MSUS}


  procedure log_harddisc_MSUS;
    begin {log_harddisc_MSUS}
      MSUS.dav.dv := 0;  {all vols will be assigned, so log only volume zero}
      log_specific_MSUS(harddisc_MSUS);
    end; {log_harddisc_MSUS}
$page$

  function any_9895_unit_missing: boolean;
    var
      temp_dav: dav_type;
      unit_missing: boolean;
    begin {any_9895_unit_missing}
      temp_dav := MSUS.dav;
      temp_dav.du := 3;  {start with unit 3 and work down}
      repeat  {see if all four units are present}
	unit_missing := scanneddevice_letter(temp_dav)<>HP9895;
	temp_dav.du := temp_dav.du-1;
      until (temp_dav.du<0) or unit_missing;
      any_9895_unit_missing := unit_missing;
    end; {any_9895_unit_missing}


  procedure search_higher_numbered_CS80_units;
    var
      temp_MSUS: MSUS_type;
    begin {search_higher_numbered_CS80_units}
      temp_MSUS := MSUS;
      with temp_MSUS, dav do
	if du<14 then  {potentially there are higher-numbered units}
	  begin
	    du := du+1;
	    dv := 0;  {always look for volume 0}
	    letter := scanneddevice_letter(dav);
	    log_MSUS(temp_MSUS, search_for_other_units);  {recurse!}
	  end; {if}
    end; {search_higher_numbered_CS80_units}


  procedure log_CS80_MSUS;
    var
      CS80dt: byte;             {device type}
      CS80id: integer;          {HP product number}
      CS80hardvols: shortint;   {number of volumes}
      CS80mp: mp_type;          {media parameters}
    const
      tape_dt = 2;
      min_hd_size = 10000000;  {bytes}
    begin {log_CS80_MSUS}
      get_CS80_parms(MSUS.dav, CS80dt, CS80id, CS80hardvols, CS80mp);
      if CS80dt=tape_dt then
	log_specific_MSUS(CS80tape_MSUS)
      else if (CS80hardvols=1) and (CS80mp.bpt*CS80mp.tpm<min_hd_size) then
	log_flpy_MSUS(assign_only_this_unit)
      else
	log_harddisc_MSUS;
    end; {log_CS80_MSUS}

  procedure search_higher_numbered_SCSI_units;          {DEW 09/89 - added SCSI support}
    var
      temp_MSUS: MSUS_type;
    begin {search_higher_numbered_SCSI_units}
      {
	search for multiple logical units on a given bus address
      }
      temp_MSUS := MSUS;
      with temp_MSUS, dav do
	if du<7 then
	  begin
	    du := du+1;
	    dv := 0;  {always look for volume 0}
	    letter := SCSIscanneddevice_letter(dav);
	    log_MSUS(temp_MSUS, search_for_other_units);  {recurse!}
	  end; {if}
    end; {search_higher_numbered_SCSI_units}


  procedure log_SCSI_MSUS;                              {DEW 09/89 - added SCSI support}
    var
      SCSIdt: byte;             {device type}
      SCSIRemovable: boolean;   {removable disk}
      SCSImp: mp_type;          {media parameters}
    begin {log_SCSI_MSUS}
      get_SCSI_parms(MSUS.dav, SCSIdt, SCSIRemovable, SCSImp);
      if SCSIdt = 0 then {disk type}
      begin
	if SCSIRemovable then
	  log_flpy_MSUS(assign_only_this_unit)
	else
	  log_harddisc_MSUS;
      end;
      {
	else tapes, printers, etc. not supported.
      }
    end; {log_SCSI_MSUS}
$page$

  begin {log_MSUS}

    zero_out_NA_fields(MSUS);

    case MSUS.letter of

      INTERNAL, HP8290X, HP9885:
	log_flpy_MSUS(assign_both_units);

{INTERNAL ONLY BEGIN}
      HP913X_A, HP913X_B, HP913X_C, HP7905, HP7906, HP7920, HP7925:
{EXTERNAL VERSION
      HP913X_A, HP913X_B, HP913X_C:
{INTERNAL ONLY END}
	log_harddisc_MSUS;

      HP9895:
	if any_9895_unit_missing then  {ultimately assign only two units }
	  log_flpy_MSUS(assign_both_units)
	else  {ultimately assign all four units (probably a 913X)}
	  begin
	    MSUS.dav.du := 0;  {log only unit zero}
	    log_harddisc_MSUS;
	  end;  {else}

      CS80:
	begin
	  if log_MSUS_option=search_for_other_units then
	    search_higher_numbered_CS80_units;
	  log_CS80_MSUS;  {distinguishes tapes, floppies, & hard discs!}
	end;

      SRM:
	SRM_dav := MSUS.dav;

      PRINTER:
	local_printer_dav := MSUS.dav;

      BUBBLE:
	BUBBLE_dav := MSUS.dav;

      SCSI:                                             {DEW 09/89 - added SCSI support}
	begin
	  if log_MSUS_option=search_for_other_units then
	    search_higher_numbered_SCSI_units;
	  log_SCSI_MSUS;  {only disks are supported right now}
	end;

      otherwise
	{do nothing};

    end; {case}

  end; {log_MSUS}
$page$

{
{ Return the suffix of the system we booted.
{ e.g. SYSTEM_xxx -> xxx
{      SYSxxxxxxx -> xxxxxxx
{ Used as suffix for sysprefix (/WORKSTATIONS/SYSTEM) when
{ setting system volume on HFS disks.
}
function syssuffix: string20;
begin
  syssuffix := bootname('', 0);
end;


{
{ determine whether a card at specified select code is 98629--SRM
{ added 870622 LAF to fix bug FSDat01185
{
{ added ability to connect up to SRMLAN support, if it exists and is
{ willing to support 98643A at select code sc. is_SRMcard will return
{ TRUE if it's SRM card, or 98643A with SRMLAN support. SFB/RDQ 1/19/89
}
function is_SRMcard(sc: integer): boolean;
const
  srmlan_symbol='LANSRM_LANSRM_OK';     {procedure in SRMLAN version of SRM}
type
  chararray = packed array [0..65535] of char;
  pchararray = ^chararray;
  proctrick_rectype = record case boolean of
	true  : (proc:procedure(var sc : integer));
	false : (entry, statlink: integer);
    end;
var
  card: pchararray;
  stat2addr: integer;
  kludgerec: record case integer of
    0: (int: integer);
    1: (adr: pchararray);
    end;
  proctrick : proctrick_rectype;
begin
try     (* recover if no card here or if not SRM *)
  is_SRMcard:=true;
  kludgerec.int := sc * hex('10000') + hex('600000');   (* card address *)
  card := kludgerec.adr;
  if ord(card^[1]) mod 128 = 52 then        (* datacomm ?? *)
    begin
      stat2addr := ord(card^[16395])*256 + ord(card^[16393]);
      if stat2addr >= 32768 then escape(0);
      if ord(card^[stat2addr*2+1]) mod 128 <> 1 then escape(0); (* not datacomm *)
      if ord(card^[hex('402f')]) <> 3 then escape(0);       (* not SRM *)
    end
  else
    begin
      proctrick.statlink:=0;
      proctrick.entry:=value(SRMLAN_SYMBOL);
      if proctrick.entry <> 0 then
	call(proctrick.proc, sc);       {SRMLAN_OK will set sc < 0 if will support
					 SRMLAN for this card.
					 Let SRMLAN_OK decide if card is 98643A}
      if sc >= 0 then escape(0);        {LANSRM will not support this sc}
    end;
recover
  is_SRMcard := false;
end;


begin {ctable}

  { various initializations }

  call(cleariohook); {init IO cards in case the BOOTROM drivers touched them}

  init_scanstuff;
  init_SCSIscanstuff;

  for index := 1 to MSUS_array_size do
    begin
      flpy_MSUS[index]     := null_MSUS;
      harddisc_MSUS[index] := null_MSUS;
      CS80tape_MSUS[index] := null_MSUS;
    end;  {for}

  SRM_dav                  := SRM_default_dav;     {overridden if bootdevice}

  BUBBLE_dav               := BUBBLE_default_dav;  {overridden if bootdevice}

  if local_printer_option=HPIB
    then local_printer_dav := local_HPIB_printer_default_dav   {scan may override}
    else if local_printer_option=RS232
    then local_printer_dav := local_RS232_printer_default_dav  {scan may override}
    else local_printer_dav := local_PARALLEL_printer_default_dav;  {scan may override}


  { log the default 9885 floppy pair, since HP-IB scanning won't include it }

  log_MSUS(HP9885_default_MSUS, search_for_other_units);


  { scan the HP-IB's for mass storage devices and possibly a local printer }

  with scanner_MSUS, dav do
    for index := 1 to sc_list_length do
      for bus_address := 0 to 7 do
	begin
	  sc := sc_list[index];
	  ba := bus_address;
	  du := 0;
	  dv := 0;
	  letter := scanneddevice_letter(dav);
	  log_MSUS(scanner_MSUS, search_for_other_units);
	end; {for}

  { scan the SCSI select codes for disks}

  with scanner_MSUS, dav do
    for index := 1 to SCSIsc_list_length do
      for bus_address := 0 to 7 do
	begin
	  sc := SCSIsc_list[index];
	  ba := bus_address;
	  du := 0;
	  dv := 0;
	  letter := SCSIscanneddevice_letter(dav);
	  log_MSUS(scanner_MSUS, search_for_other_units);
	end; {for}


  { log internal mini if present, since HP-IB scanning didn't include it }

  if internal_mini_present then
    log_MSUS(INTERNAL_MSUS, search_for_other_units);


  { check sc 21 for SRM, scan for it if it's not there, keep lowest sc }
  { added 870622 LAF to fix bug FSDat01185 }

  if not is_SRMcard(SRM_dav.sc) then
    for select_code:=31 downto 7 do
      if is_SRMcard(select_code) then
	SRM_dav.sc:=select_code;


  { get the bootdevice MSUS & log it }

  get_bootdevice_MSUS(bootdev_MSUS);
  zero_out_NA_fields(bootdev_MSUS);  {for tea routine comparisons}
  log_MSUS(bootdev_MSUS, do_not_search_for_other_units);
  bootdev_lun := 0;  {set otherwise if/when bootdevice is assigned in tea}
$page$

  { Create a temporary table & fill it with dummy entries }

  create_temp_unitable;


  { standard assignments: avoid changing }

  tea_memory_volume_dam(primary_dam);

  tea_crt( 1);
  tea_kbd( 2);

  assign_flpy_unit_pair( 3, primary_dam, {flpy_MSUS[]} 1);

  with SRM_dav do
    tea_srm( 5, sc, ba, du);

  with local_printer_dav do
    tea_local_printer( 6, sc, ba, {uvid} 'PRINTER', local_printer_timeout);


  { optional floppy unit pairs }

  for index := 2 to floppy_unit_pairs do
    assign_flpy_unit_pair(7+(index-2)*2, primary_dam, {flpy_MSUS[]} index);

$page$

  { local hard discs }

  $if true$

    lun := first_harddisc_lun-1;

    for index := 1 to MSUS_array_size do
      with harddisc_MSUS[index], dav do
	case letter of

	  HP9895: {9895 ident with all four units present; probably a HP913X}
	    for i := 0 to 3 do
	      if increment_and_test_lun then
		tea_HP9895(lun, primary_dam, sc, ba, {du} i, {block_offset} 0);

{INTERNAL ONLY BEGIN}
	  HP913X_A, HP913X_B, HP913X_C, HP7920, HP7925:
{EXTERNAL VERSION
	  HP913X_A, HP913X_B, HP913X_C:
{INTERNAL ONLY END}
	    begin
	      mp := medium_parameters(letter);
	      pp := partitioning_parameters(letter);
	      nvols := number_vols(mp, pp);
	      hfs_installed := false;
	      for i := 0 to nvols-1 do
		if not hfs_installed and increment_and_test_lun then
		  tea_amigo_sv(lun, primary_dam, sc, ba, du,
				    vol_offset(i, nvols, mp),
				    letter,
				    vol_bytes(i, nvols, mp));
	    end;

{INTERNAL ONLY BEGIN}
	  HP7905, HP7906:
	    begin
	      mp := medium_parameters(letter);
	      pp := partitioning_parameters(letter);
	      repeat
		nvols := number_vols(mp, pp);
		hfs_installed := false;
		for i := 0 to nvols-1 do
		  if not hfs_installed and increment_and_test_lun then
		    tea_amigo_mv(lun, primary_dam, sc, ba, du, dv,
				      vol_offset(i, nvols, mp),
				      letter,
				      vol_bytes(i, nvols, mp));
		if letter=HP7905 then  {adjust for its half-size fixed portion}
		  mp.tpm := mp.tpm div 2;
		dv := dv+1;
	      until dv>=2;
	    end;
{INTERNAL ONLY END}

	  CS80:
	    begin
	      pp := partitioning_parameters(letter);
	      repeat
		get_CS80_parms(dav, CS80dt, CS80id, CS80hardvols, mp);
		if mp.tpm=1 then  {track partitioning info unavailable...}
		  mp := block_boundaries(mp);  {will have to fake it!}
		nvols := number_vols(mp, pp);
		hfs_installed := false;
		for i := 0 to nvols-1 do
		  if not hfs_installed and increment_and_test_lun then
		    tea_CS80_mv(lun, primary_dam, sc, ba, du, dv,
				     vol_offset(i, nvols, mp),
				     {devid} CS80id,
				     vol_bytes(i, nvols, mp),
				     mp.tpm*mp.bpt);
		dv := dv+1;
	      until dv>=CS80hardvols;
	    end;

	  SCSI:
	    begin
		pp := partitioning_parameters(letter);
		get_SCSI_parms(dav, SCSIdt, SCSIRemovable, mp);
		nvols := number_vols(mp, pp);
		hfs_installed := false;
		for i := 0 to nvols-1 do
		  if not hfs_installed and increment_and_test_lun then
		    tea_SCSI_mv(lun, primary_dam, sc, ba, du, dv,
				     vol_offset(i, nvols, mp),
				     {devid} SCSIdt,
				     vol_bytes(i, nvols, mp),
				     mp.tpm*mp.bpt);
	    end;

	  otherwise
	    {no local hard disc logged};

	end; {case}

  $end$  { local hard discs }


  { CS80 tapes }

  $if true$

    with CS80tape_MSUS[1], dav do
      if letter=CS80 then
	tea_CS80_sv(41, LIF_dam, sc, ba, du, dv);

    with CS80tape_MSUS[2], dav do
      if letter=CS80 then
	tea_CS80_sv(42, LIF_dam, sc, ba, du, dv);

  $end$  { CS80 tapes }


  { secondary directory access method entries for highest priority floppies }

  assign_flpy_unit_pair(43, secondary_dam, {flpy_MSUS[]} 1);

  { secondary directory access method entries for additional floppies }

  assign_flpy_unit_pair(47, secondary_dam, {flpy_MSUS[]} 2);

  assign_flpy_unit_pair(49, secondary_dam, {flpy_MSUS[]} 3);



  { duplicate entries for prefixing down the SRM }

{INTERNAL ONLY BEGIN}
  (***********************************************************************)
  (*  NOTE:  Additional duplicate SRM entries may be assigned here, then *)
  (*    prefixed down below after assigning the temp_unitable.  However  *)
  (*    for correct behavior in assigning the system unit, specifically  *)
  (*    if booting off the SRM, unit #45 must be the assigned AFTER all  *)
  (*    the other SRM units have been assigned!                          *)
  (*                                                                     *)
  (*    You may assign both "real" SRM and SRM-UX units with this code.  *)
  (*    You must put in the correct unit number, select code, bus        *)
  (*    address (really SRM host node number), and du (really SRM disc   *)
  (*    volume number or SRM-UX emulated disc volume number.)            *)
  (*                                                                     *)
  (*    Unit numbers 46 through 50 are often available for use as        *)
  (*    additional SRM or SRM-UX entries, especially if you have no      *)
  (*    more than one floppy unit pair, and you are not booting from an  *)
  (*    HFS hard disc.                                                   *)
  (*                                                                     *)
  (*    SRM volume information is available from the SRM console.        *)
  (*    SRM-UX volume emulation information is available from the        *)
  (*    HP-UX file "/etc/srmconf" on the SRM-UX server machine.          *)
  (***********************************************************************)
{INTERNAL ONLY END}

  with SRM_dav do
    begin
      {  tea_srm(46, sc, ba, du);  {free unless booting from HFS hard disc}
      tea_srm(45, sc, ba, du);  {for possible use as the system unit}
    end; {with}

$page$

  { templates for "manually" specifying mass storage table entry assignments }


  $if false$ { internal minifloppy in a 9826/9836 }
    tea_mini( 3, primary_dam, {du} 0);
    tea_mini( 4, primary_dam, {du} 1);
  $end$

  $if false$ { HP8290X, HP9121, or the floppy in an HP913X }
    tea_HP8290X( 3, primary_dam, {sc}  7, {ba} 0, {du} 0);
    tea_HP8290X( 4, primary_dam, {sc}  7, {ba} 0, {du} 1);
  $end$

  $if false$ { HP9895 }
    tea_HP9895( 7, primary_dam, {sc}  7, {ba} 0, {du} 0, {block_offset} 0);
    tea_HP9895( 8, primary_dam, {sc}  7, {ba} 0, {du} 1, {block_offset} 0);
  $end$

  $if false$ { HP913X (four volume 9895 look-a-like version) }
    for i := 0 to 3 do
      tea_HP9895(11+i, primary_dam, {sc}  7, {ba} 0, {du} i, {block_offset} 0);
  $end$

  $if false$ { HP913X_A (5 Mbyte single volume version) }
    mp := medium_parameters(HP913X_A);
    nvols := 4;
    for i := 0 to nvols-1 do
      tea_amigo_sv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0,
			 vol_offset(i, nvols, mp),
			 HP913X_A,
			 vol_bytes(i, nvols, mp));
  $end$

  $if false$ { HP913X_B (10 Mbyte single volume version) }
    mp := medium_parameters(HP913X_B);
    nvols := 9;
    for i := 0 to nvols-1 do
      tea_amigo_sv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0,
			 vol_offset(i, nvols, mp),
			 HP913X_B,
			 vol_bytes(i, nvols, mp));
  $end$

  $if false$ { HP913X_C (15 Mbyte single volume version) }
    mp := medium_parameters(HP913X_C);
    nvols := 14;
    for i := 0 to nvols-1 do
      tea_amigo_sv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0,
			 vol_offset(i, nvols, mp),
			 HP913X_C,
			 vol_bytes(i, nvols, mp));
  $end$
$page$

{INTERNAL ONLY BEGIN}
  $if false$ { HP7905 }
    mp := medium_parameters(HP7905);
    { mp := block_boundaries(mp);  {override track boundary partitioning}
    nvols := 10;
    for i := 0 to nvols-1 do  {assign removable medium entries}
      tea_amigo_mv (11+i, primary_dam, {sc} 14, {ba} 0, {du} 0, {dv} 0,
			  {offset} vol_offset(i, nvols, mp),
			  {letter} HP7905,
			  {umaxbytes} vol_bytes(i, nvols, mp));
    mp.tpm := mp.tpm div 2;  {fixed only half size}
    nvols := 5;
    for i := 0 to nvols-1 do  {assign fixed medium entries}
      tea_amigo_mv (21+i, primary_dam, {sc} 14, {ba} 0, {du} 0, {dv} 1,
			  {offset} vol_offset(i, nvols, mp),
			  {letter} HP7905,
			  {umaxbytes} vol_bytes(i, nvols, mp));
  $end$

  $if false$ { HP7906 }
    mp := medium_parameters(HP7906);
    { mp := block_boundaries(mp);  {override track boundary partitioning}
    nvols := 10;
    for i := 0 to nvols-1 do  {assign removable medium entries}
      tea_amigo_mv (11+i, primary_dam, {sc} 14, {ba} 0, {du} 0, {dv} 0,
			  {offset} vol_offset(i, nvols, mp),
			  {letter} HP7906,
			  {umaxbytes} vol_bytes(i, nvols, mp));
    for i := 0 to nvols-1 do  {assign fixed medium entries}
      tea_amigo_mv (21+i, primary_dam, {sc} 14, {ba} 0, {du} 0, {dv} 1,
			  {offset} vol_offset(i, nvols, mp),
			  {letter} HP7906,
			  {umaxbytes} vol_bytes(i, nvols, mp));
  $end$

  $if false$ { HP7920 }
    mp := medium_parameters(HP7920);
    { mp := block_boundaries(mp);  {override track boundary partitioning}
    nvols := 30;
    for i := 0 to nvols-1 do
      tea_amigo_sv(11+i, primary_dam, {sc} 14, {ba} 0, {du} 0,
			 {offset} vol_offset(i, nvols, mp),
			 {letter} HP7920,
			 {umaxbytes} vol_bytes(i, nvols, mp));
  $end$

  $if false$ { HP7925 }
    mp := medium_parameters(HP7925);
    { mp := block_boundaries(mp);  {override track boundary partitioning}
    nvols := 30;
    for i := 0 to nvols-1 do
      tea_amigo_sv(11+i, primary_dam, {sc} 14, {ba} 0, {du} 0,
			 {offset} vol_offset(i, nvols, mp),
			 {letter} HP7925,
			 {umaxbytes} vol_bytes(i, nvols, mp));
  $end$
{INTERNAL ONLY END}
$page$

  $if false$ { current CS/80 discs "soft" partitioned by the host }
      CS80id := 7908; nvols := 16; mp.tpm :=  5* 370; mp.bpt := 35*256;  {7908}
    { CS80id := 7911; nvols := 27; mp.tpm :=  3* 572; mp.bpt := 64*256;  {7911}
    { CS80id := 7912; nvols := 30; mp.tpm :=  7* 572; mp.bpt := 64*256;  {7912}
    { CS80id := 7914; nvols := 30; mp.tpm :=  7*1152; mp.bpt := 64*256;  {7914}
    { CS80id := 7933; nvols := 30; mp.tpm := 13*1321; mp.bpt := 92*256;  {7933}
    { CS80id := 7935; nvols := 30; mp.tpm := 13*1321; mp.bpt := 92*256;  {7935}
    { mp := block_boundaries(mp);  {override track boundary partitioning}
    hfs_installed:=false;
    for i := 0 to nvols-1 do
      if not hfs_installed then
	tea_CS80_mv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0, {dv} 0,
			  vol_offset(i, nvols, mp),
			  {devid} CS80id,
			  vol_bytes(i, nvols, mp),
			  mp.tpm*mp.bpt);
  $end$


  $if false$ { current CS/80 discs "hard" partitioned by the device }
      CS80hardvols :=  3;
      for i := 0 to CS80hardvols-1 do
	tea_CS80_sv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0, {dv} i);
  $end$


  $if false$ { Command Set/80 floppy }
    tea_CS80_sv( 3, primary_dam, {sc}  7, {ba} 0, {du} 0, {dv} 0);
  $end$


  $if false$ { Command Set/80 tape }
    tea_CS80_sv(41, LIF_dam, {sc}  7, {ba} 0, {du} 1, {dv} 0);
  $end$


  $if false$ { BUBBLE memory }
    {watch for conflicting uses of unit 42}
    {BUBBLE_DAV.SC default is 30 but may have been changed to boot SC}
    tea_BUBBLE(42,primary_dam,BUBBLE_dav.SC);
  $end$


  $if false$ { EPROM DISC }
    {watch for conflicting uses of unit 42}
    tea_EPROM(42,primary_dam,{ sequence number } 0);
  $end$


  { end of templates }
$page$

  { assign the new unitable and unitclear all units }

  assign_temp_unitable;

  { prefix the primary and secondary SRM unit entries }

  if not unit_prefix_successful('#5:/') then
    {do nothing};  {tries to set up uvid for possible default unit assignment below}

  { if not unit_prefix_successful('#46:/?') then zap_assigned_unit(46);}
  {NOTE: DO NOT UNCOMMENT THE ABOVE LINE IF YOU BOOT FROM AN HFS DISC! }

  if not unit_prefix_successful('#45:'+sysprefix+srmnode(unitable^[45].sc)) then
    if not unit_prefix_successful('#45:'+sysprefix) then
      zap_assigned_unit(45);


  { remove extraneous local hard disc entries if necessary }

  lun2 := first_harddisc_lun;
  while lun2<last_harddisc_lun do
    begin
      lun1 := lun2;
      repeat
	lun2 := lun2+1;
      until (lun2>last_harddisc_lun) or not on_same_medium(lun1, lun2);
      pp := partitioning_parameters(unitable^[lun1].letter);
      if pp.mnv<-1 then
	remove_extraneous_volumes(lun1, lun2-1);
    end; {while}


  { assign the system unit }

  if specified_system_unit<>0 then
    ok := sysunit_ok(specified_system_unit)
  else if (bootdev_lun<>0) and (unitable^[bootdev_lun].umaxbytes>300000) then
    ok := sysunit_ok(bootdev_lun)
  else  {search for a more suitable system unit}
    begin
      index := 0;
      repeat
	index := index+1;
	ok := sysunit_ok(sysunit_list[index]);
      until ok or (index>=sysunit_list_length);
      if not ok then  {revert back to boot device, hoping it was identified}
	ok := sysunit_ok(bootdev_lun);
    end; {else}


  { special case for default unit assignment }

  if sysunit=45 then  {set the default unit to the primary SRM unit entry}
    dkvid := unitable^[5].uvid;
$page$
  { rearrange things for HFS }
  if h_unitable <> nil then with h_unitable^ do begin

      { if booted from HFS, need to reset syvid and dkvid       }
      { also, try to set sysvolume to #46:/WORKSTATIONS/SYSTEM*  }
      if unitable^[sysunit].uisfixed
      and tbl[sysunit].is_hfsunit
      and sysunit_ok(sysunit) then begin
	lun := sysunit;
	extra_HFS_unit(sysunit, 46, sysprefix+syssuffix);
	if not tbl[46].is_hfsunit then
	  extra_HFS_unit(sysunit, 46, sysprefix);
	if tbl[46].is_hfsunit and sysunit_ok(46) then
	  dkvid := unitable^[lun].uvid;
      end;

      { At this point, there is only one HFS unit per disc, except    }
      { on the system disc (if it's HFS), where there are two -- one  }
      { at /WORKSTATIONS/SYSTEM, the other at /.  Add more as         }
      { follows:                                                      }
      { extra_HFS_unit(old unit #, new unit #, prefix)                }
      { "new unit" then becomes a unit on the same disc as "old unit",}
      { which must already exist.  This fails unless new unit is not  }
      { yet used, or if the prefix fails.  The prefix should not in-  }
      { clude a volume name or number.                                }
      { Example:                                                      }
      {         extra_HFS_unit(11, 12, '/PROGS');                     }

  end;

  { re-open the standard system files }
  openfiles;

end. {ctable}
@


53.2
log
@Updated copyright message.
@
text
@@


53.1
log
@Automatic bump of revision number for PWS version 3.24B
@
text
@d4 1
a4 1
1984, 1985, 1987, 1989, 1990.
@


52.1
log
@Automatic bump of revision number for PWS version 3.24A
@
text
@@


51.1
log
@Automatic bump of revision number for PWS version 3.24d
@
text
@@


50.1
log
@Automatic bump of revision number for PWS version 3.23c
@
text
@@


49.1
log
@Automatic bump of revision number for PWS version 3.24b
@
text
@@


48.1
log
@Automatic bump of revision number for PWS version 3.24a
@
text
@@


47.1
log
@Automatic bump of revision number for PWS version 3.23
@
text
@@


46.1
log
@Automatic bump of revision number for PWS version 3.23
@
text
@@


45.1
log
@Automatic bump of revision number for PWS version 3.23C
@
text
@@


44.2
log
@

       Updated copyright dates at the head of the file.
@
text
@@


44.1
log
@Automatic bump of revision number for PWS version 3.23B
@
text
@d4 1
a4 1
1984, 1985, 1987.
@


43.1
log
@Automatic bump of revision number for PWS version 3.23aA
@
text
@@


42.3
log
@Update call to ScsiSBInit to match the modification made to SCSILIB, that
is, instead of using a pointer to the unit table, use a pointer to a DAV.
@
text
@@


42.2
log
@Added comments to CTABLE which more correctly reflect the SCSI and PARALLEL
modifications to CTABLE for 3.23.
@
text
@d1673 1
a1673 1
			call(ScsiSBInitProc.SBInit, pSB, pUnit);
@


42.1
log
@Automatic bump of revision number for PWS version 3.23e
@
text
@d113 2
d125 1
a125 1
	10000;  {10 seconds recomended for Laser Jet}
d280 3
a282 2
    2: CTABLE will attempt the PREVENT MEDIUM REMOVAL command.  The SCSI utility
       program, SCSIALLOW, will enable the removable media to be removed.
d1559 8
@


41.3
log
@The default SCSIRemovableOption should be AllOver10MAreHard, not
AllAreFloppy.
@
text
@@


41.2
log
@Updated CTABLE to conform to nomenclature modification from SCSIIF
to SCSILIB.
@
text
@d290 1
a290 1
	SCSIRemovableOption = AllAreFloppy;
@


41.1
log
@Automatic bump of revision number for PWS version 3.23d
@
text
@d1609 1
a1609 1
	SCSIIFinMemory:boolean;
d1616 7
a1622 7
	IsScsiCardProc.value            := value('SCSIIF_ISSCSICARD');
	ScsiSBSizeProc.value            := value('SCSIIF_SCSISBSIZE');
	ScsiSBInitProc.value            := value('SCSIIF_SCSISBINIT');
	ScsiCheckDevProc.value          := value('SCSIIF_SCSICHECKDEV');
	ScsiDevInfoProc.value           := value('SCSIIF_SCSIDEVINFO');
	ScsiDiscSizeProc.value          := value('SCSIIF_SCSIDISCSIZE');
	ScsiPreventProc.value           := value('SCSIIF_SCSIDISCPREVENT');
d1624 1
a1624 1
	SCSIIFinMemory :=       (IsScsiCardProc.value <> 0) and
d1632 1
a1632 1
	if SCSIIFinMemory then
d1656 1
a1656 1
	if SCSIIFinMemory then
@


40.4
log
@Added support for the PARALLEL interface.
@
text
@@


40.3
log
@ o Added Select Code 28 to SCSI search list.
 o Added SCSIRemovableOptions and handling.
 o Added call to SCSIDiscPrevent for floppys being treated like a hard disc.
 o Allow a SCSI floppy without media in it to recieve an entry in the
   unitable.
@
text
@d93 1
a93 1
    local_printer_type = (HPIB, RS232);
d122 3
d145 2
d2145 3
a2147 1
    else local_printer_dav := local_RS232_printer_default_dav; {scan may override}
@


40.2
log
@Updated CTABLE to work with the latest SCSI programmer's interface
definition.
@
text
@d244 1
a244 1
      2;
d252 2
a253 1
	  15];   {external SCSI sc when internal HP-IB/SCSI present at sc 14}
d255 7
d263 26
d698 9
d709 1
d1559 1
a1559 1
				 var SCSIremovable:boolean;
d1580 1
d1590 1
d1599 2
a1600 1
	ScsiDiscSizeProc:ScsiProcType;
d1617 1
d1624 2
a1625 1
				(ScsiDiscSizeProc.value <> 0);
d1659 3
a1661 1
			if (ioresult = ord(inoerror)) or (ioresult = ord(zmediumchanged)) then
d1671 1
a1671 1
			 var SCSIremovable:boolean;
d1678 1
d1680 1
d1683 1
a1683 1
		call(ScsiDevInfoProc.DevInfo, pSB, dt, ansi, SCSIremovable, s);
d1688 5
d1694 20
a1713 3
		if ioresult <> ord(inoerror) then goto 1;
		SCSImp.tpm := ntpc * nc;
		SCSImp.bpt := nbps * nspt;
d1719 1
d1724 6
d1779 1
a1779 1
  SCSIremovable:boolean;
d1979 1
a1979 1
      SCSIremovable: boolean;   {removable disk}
d1982 1
a1982 1
      get_SCSI_parms(MSUS.dav, SCSIdt, SCSIremovable, SCSImp);
d1985 1
a1985 1
	if SCSIremovable then
d2305 1
a2305 1
		get_SCSI_parms(dav, SCSIdt, SCSIremovable, mp);
@


40.1
log
@Automatic bump of revision number for PWS version 3.23c
@
text
@d413 1
a413 1
  SCSIDSK_TM_name     = 'SCSIDISKMODULE_SCSIDISK';{09/89 DEW - added SCSI support}
d1046 1
a1046 1
    tea(un,dam(ds),SCSIDSK_TM_name,sc,ba,du,dv,os,id,'',SCSI,F,F,T,mb,disksize);
d1066 1
a1066 1
    tea(un,dam(ds),SCSIDSK_TM_name,sc,ba,du,dv,0,-1,'',SCSI,F,F,T,0,0);
d1533 1
a1533 1
	ScsiDiskSizeType        = procedure(    pSB:ANYPTR;
d1544 1
a1544 1
						6:(DiskSize:ScsiDiskSizeType);
d1553 1
a1553 1
	ScsiDiskSizeProc:ScsiProcType;
d1569 1
a1569 1
	ScsiDiskSizeProc.value          := value('SCSIIF_SCSIDISKSIZE');
d1576 1
a1576 1
				(ScsiDiskSizeProc.value <> 0);
d1635 1
a1635 1
		call(ScsiDiskSizeProc.DiskSize, pSB, nbps, nspt, ntpc, nc);
@


39.2
log
@

      3.23 SRM-UX source control hacking.
@
text
@@


39.1
log
@Automatic bump of revision number for PWS version 3.23b
@
text
@d2272 1
d2294 1
@


38.2
log
@Added SCSI autoconfiguration.
@
text
@@


38.1
log
@Automatic bump of revision number for PWS version 3.23a
@
text
@d204 2
d241 12
d254 1
d294 1
d380 3
d413 1
d801 1
d1032 38
d1076 1
d1315 1
a1315 1
	  HP913X_B, HP913X_C, HP7905,   HP7906,   HP7920,   HP7925,   NODEVICE, NODEVICE,
d1317 1
a1317 1
	  HP913X_B, HP913X_C, NODEVICE, NODEVICE, NODEVICE, NODEVICE, NODEVICE, NODEVICE,
d1336 1
a1336 1
	  if MSUS.letter in [HP7905, HP7906, CS80] then
d1338 1
a1338 1
	  if MSUS.letter = CS80 then
d1506 149
d1665 1
a1665 1
  sysglobals, fs, ldr, options, ctr, BRstuff, scanstuff, bootDAMmodule;
d1696 2
d1748 1
a1748 1
      otherwise  {includes HP7905, HP7906, CS80}
d1874 38
d1955 7
d2043 1
d2080 1
d2082 13
d2218 15
@


37.1
log
@Automatic bump of revision number for PWS version 3.3a
@
text
@@


36.2
log
@First version meant to support SRM-UX. Supports only #5 and #45 from
boot or from sc=21 as default. Supports only vol=8 as default. Host node
=0 as default.

Scott
@
text
@@


36.1
log
@Automatic bump of revision number for PWS version 3.22
@
text
@d880 1
a880 1
    check(ba, 0, 63);
d1268 1
a1268 1
	    if dev=d1
d1730 4
d1736 2
d1741 4
d1752 1
d1755 1
d1758 17
a1774 6
  if ord(card^[1]) mod 128 <> 52 then escape(0);        (* not datacomm *)
  stat2addr := ord(card^[16395])*256 + ord(card^[16393]);
  if stat2addr >= 32768 then escape(0);
  if ord(card^[stat2addr*2+1]) mod 128 <> 1 then escape(0); (* not datacomm *)
  if ord(card^[hex('402f')]) <> 3 then escape(0);       (* not SRM *)
  is_SRMcard := true;
d1976 1
d1978 6
d1992 14
a2013 6

  { secondary directory access method entries for additional floppies }

  assign_flpy_unit_pair(47, secondary_dam, {flpy_MSUS[]} 2);

  assign_flpy_unit_pair(49, secondary_dam, {flpy_MSUS[]} 3);
@


35.1
log
@Automatic bump of revision number for PWS version 3.22
@
text
@@


34.1
log
@Automatic bump of revision number for PWS version 3.22
@
text
@@


33.1
log
@Automatic bump of revision number for PWS version 3.22D
@
text
@@


32.1
log
@Automatic bump of revision number for PWS version 3.22C
@
text
@@


31.1
log
@Automatic bump of revision number for PWS version 3.22B
@
text
@@


30.1
log
@Automatic bump of revision number for PWS version 3.22A
@
text
@@


29.1
log
@Automatic bump of revision number for PWS version 3.22b
@
text
@@


28.1
log
@Automatic bump of revision number for PWS version 3.3b
@
text
@@


27.1
log
@Automatic bump of revision number for PWS version 3.3a
@
text
@@


26.1
log
@Automatic bump of revision number for PWS version 3.3 Synch
@
text
@@


25.1
log
@Automatic bump of revision number for PWS version 3.2Y
@
text
@@


24.1
log
@Automatic bump of revision number for PWS version 3.2
@
text
@@


23.1
log
@Automatic bump of revision number for PWS version 3.2P
@
text
@@


22.1
log
@Automatic bump of revision number for PWS version 3.2N
@
text
@@


21.1
log
@Automatic bump of revision number for PWS version 3.2M
@
text
@@


20.1
log
@Automatic bump of revision number for PWS version 3.2L
@
text
@@


19.3
log
@search for SRM if it's not at default SC
fix for dts bug FSDat01185
@
text
@@


19.2
log
@Fix to work around booting problems when booting from SRM with coax
interface, processor is 320 or faster, and non-existent discs are
configured in the CTABLE.
@
text
@d1482 1
a1482 1
  index, bus_address, i, nvols: shortint;
d1727 30
d1805 9
@


19.1
log
@Automatic bump of revision number for PWS version 3.2K
@
text
@d400 2
d1070 1
@


18.1
log
@Automatic bump of revision number for PWS version 3.2J
@
text
@@


17.1
log
@Automatic bump of revision number for PWS version 3.2I+
@
text
@@


16.1
log
@Automatic bump of revision number for PWS version 3.2I
@
text
@@


15.2
log
@Fixed #47 dam=0 problem, as well as requesting HFS on non-0 byteoffset
unit. Also protected extra_HFS_unit against nil h_unitable pointer.
@
text
@@


15.1
log
@Automatic bump of revision number for PWS version 3.2H
@
text
@d474 3
d603 1
a603 1
      dam_name := NO_DAM_name;  {was LIF_DAM_name. SFB}
d687 9
a695 2
    if (not temp_h_unitable^.tbl[un].is_hfsunit) and (dam_proc.value=0) then
     temp_unitable^[un]:=old_unit; {if not, uninstall the entry. SFB}
@


14.2
log
@Fixed case where LIFDAM not in INITLIB, HFS_DAM would not install on
hard disc with superblock. Also corrected test for bootdev_lun
candidacy.
@
text
@@


14.1
log
@Automatic bump of revision number for PWS version 3.2G
@
text
@d578 8
d600 1
a600 1
      dam_name := LIF_DAM_name;
d608 5
a612 1
    if (dam_proc.value<>0) and (tm_proc.value<>0) then  {assign the entry}
d642 1
a642 1
	  dam_ok := (dam_name=HFS_DAM_name)
d644 2
a645 1
	  dam_ok := (dam_name=LIF_DAM_name) or (dam_name=SRM_DAM_name);
d664 1
a664 1
	  and (dam_name = LIF_DAM_name)
d682 5
d1479 1
a2176 1

@


13.2
log
@Fix CS80 template, remove commented directives, add comments.
@
text
@@


13.1
log
@Automatic bump of revision number for PWS version 3.2F
@
text
@d216 1
a216 1
	  first_harddisc_lun,
d310 2
a311 2
      ( primary_dam,     {either LIF or UCSD, as specified in options}
	secondary_dam,   {the one not selected as primary}
a533 1
{$end$}
d535 1
d1783 1
a1783 1
  {$if true$}
d1860 1
a1860 1
  {$end$  { local hard discs }
d1865 1
a1865 1
  {$if true$}
d1875 1
a1875 1
  {$end$  { CS80 tapes }
d1895 1
a1895 1
      {  tea_srm(46, sc, ba, du);  {free}
d2028 1
d2030 6
a2035 5
      tea_CS80_mv(11+i, primary_dam, {sc}  7, {ba} 0, {du} 0, {dv} 0,
			vol_offset(i, nvols, mp),
			{devid} CS80id,
			vol_bytes(i, nvols, mp),
			mp.tpm*mp.bpt);
d2081 2
a2082 1
  { if not unit_prefix_successful('#46:/?') then zap_assigned_unit(46);  {free}
d2156 1
a2156 1
{$end$}
@


12.1
log
@Automatic bump of revision number for PWS version 3.2E
@
text
@@


11.4
log
@Redo comments on INTERFACE search.
@
text
@@


11.3
log
@Fix FSDat00571: Comments on INTERFACE search.
Also revised copyright dates and restricted
rights legend.
@
text
@d26 14
a39 13
(**********************************************)
(*                                            *)
(*  Note: You will need to use the following  *)
(*  compiler directive if the 'INTERFACE'     *)
(*  file is not in your current LIBRARY.      *)
(*  Modify the volume name as necessary for   *)
(*  your configuration. If you are using      *)
(*  double-sided 3-1/2" media, the INTERFACE  *)
(*  file will be found on the ACCESS: volume. *)
(*                                            *)
(*  $search  'CONFIG:INTERFACE.'$             *)
(*                                            *)
(**********************************************)
@


11.2
log
@Fix for FSDat00897 -- >1 HFS RAM volume fails
@
text
@d3 2
a4 1
 (c) Copyright Hewlett-Packard Company, 1985.
d13 1
a13 1
Use, duplication, or disclosure by the Government
d15 5
a19 3
paragraph (b) (3) (B) of the Rights in Technical
Data and Computer Software clause in
DAR 7-104.9(a).
a20 2
HEWLETT-PACKARD COMPANY
Fort Collins, Colorado                         *)
a21 1

d32 3
a34 1
(*  your configuration.                       *)
@


11.1
log
@Automatic bump of revision number for PWS version 3.2D
@
text
@d1111 1
a1111 1
			(letter=uep^.letter);
@


10.1
log
@Automatic bump of revision number for PWS version 3.2C
@
text
@@


9.4
log
@Fix for floppy boot -- look at hfsbflg
@
text
@@


9.3
log
@Fix for FSDat00603 -- #46 not allowed on removeable media
@
text
@d252 1
a252 1
  sysglobals, loader, options, ldr, fs;
d573 2
d626 5
d634 1
a634 1
	     ((dam_name=LIF_DAM_name) or (p_letter=SRM)) and
@


9.2
log
@Fixes for FSDat00599
@
text
@d2119 3
a2121 1
      if tbl[sysunit].is_hfsunit and sysunit_ok(sysunit) then begin
@


9.1
log
@Automatic bump of revision number for PWS version 3.2B
@
text
@d1679 1
a1679 7
function syssuffix: string255;
const
    longbase = 'SYSTEM_';
    shortbase = 'SYS';
var
    suffix: string255;
    i, j: integer;
d1681 1
a1681 18
    i := 1;
    while (i <= strlen(longbase)) and (longbase[i] = sysname[i]) do
	i := i + 1;
    if (i-1 = strlen(longbase)) or (i-1 = strlen(shortbase)) then begin
	setstrlen(suffix, 0);
	j := 1;
	while i <= 10 do begin
	    if (sysname[i] <> ' ') then begin
		setstrlen(suffix, j);
		suffix[j] := sysname[i];
		j := j + 1;
	    end;
	    i := i + 1;
	end;
	syssuffix := suffix;
    end
    else
	syssuffix := '';
a1682 1

@


8.2
log
@Fixes for FSDat00589,612 RAM Volume problems and 604 -- moved
cacher calls out of area explained to user.
@
text
@@


8.1
log
@Automatic bump of revision number for PWS version 3.2A
@
text
@d395 1
d397 8
a520 1
	unitable^[un].dam := dam_proc.dam;
d523 5
a527 1
	unitable^[un].tm := tm_proc.tm;
d633 1
a646 2
	  swap_temp_and_real_unit;

d650 1
a650 1
	      temp_unitable^[un].umaxbytes := p_disksize;
d654 2
d1009 8
d1030 2
d1072 5
a1716 3
  if h_unitable <> nil then
    call(h_unitable^.init_cache_proc);

a2086 4

  { configure HFS cache }
  if h_unitable <> nil then
    call(h_unitable^.config_cache_proc);
@


7.1
log
@Automatic bump of revision number for PWS version 3.2l
@
text
@@


6.1
log
@Automatic bump of revision number for PWS version 3.2k
@
text
@@


5.1
log
@Automatic bump of revision number for PWS version 3.2j
@
text
@@


4.3
log
@Use comments to distinguish customer version from internal version,
which supports more devices.  The program MKCTBETA produces the
customer version, 
using the comments.  This is done in TURNIT.
@
text
@@


4.2
log
@Fix bug whereby HFS floppies would get HFSDAM but not HFSTM.
@
text
@d53 8
a60 3
{set "beta" to true to get CTBETA (=customer CTABLE) changes}
  const
    beta = false;
d189 1
a189 1
$if not beta$
d198 1
a198 1
$end$
d264 1
a264 1
$if not beta$
d269 1
a269 1
$end$
d352 1
a352 1
$if not beta$
d354 1
a354 1
$end$
d683 1
a683 1
$if not beta$
d688 1
a688 1
$end$
d701 1
a701 1
  $if not beta$
d706 1
a706 1
  $end$
d721 1
a721 1
$if not beta$
d726 1
a726 1
$end$
d887 3
a889 1
$if beta$
d891 1
a891 4
$end$
$if not beta$
    if not (lr in [HP913X_A, HP913X_B, HP913X_C, HP7920, HP7925]) then
$end$
d901 1
a901 1
$if not beta$
d919 1
a919 1
$end$
d1185 3
a1187 1
$if beta$
d1189 1
a1189 4
$end$
$if not beta$
	  HP913X_B, HP913X_C, HP7905,   HP7906,   HP7920,   HP7925,   NODEVICE, NODEVICE,
$end$
d1206 3
a1208 1
$if beta$
d1210 1
a1210 4
$end$
$if not beta$
	  if MSUS.letter in [HP7905, HP7906, CS80] then
$end$
d1457 3
a1459 1
$if beta$
d1461 1
a1461 4
$end$
$if not beta$
      HP9895, HP8290X, HP913X_A, HP913X_B, HP913X_C, HP7920, HP7925, SRM:
$end$
d1604 3
a1606 1
$if beta$
d1608 1
a1608 4
$end$
$if not beta$
      HP913X_A, HP913X_B, HP913X_C, HP7905, HP7906, HP7920, HP7925:
$end$
d1785 3
a1787 1
$if beta$
d1789 1
a1789 4
$end$
$if not beta$
	  HP913X_A, HP913X_B, HP913X_C, HP7920, HP7925:
$end$
d1803 1
a1803 1
$if not beta$
d1822 1
a1822 1
$end$
d1950 1
a1950 1
{$if not beta} {$if doesn't nest!!!}
d2006 1
a2006 1
{$end$} {not beta}
@


4.1
log
@Automatic bump of revision number for PWS version 3.2i
@
text
@d330 1
a330 1
  procedure auto_install_HFS(un: unitnum);
d483 3
a485 2
{ Check this unit for an HFS superblock.  If it's got one,
{ install HFS.
d487 1
a487 1
procedure auto_install_HFS(un: unitnum);
d501 10
a510 12
    if h_unitable <> nil then with h_unitable^ do
      if not tbl[un].is_hfsunit then begin
	call(init_unit_proc, un, false);
	{ init_unit_proc sets is_hfsunit if recognized }
	if tbl[un].is_hfsunit then begin
	  dam_proc.value := value(HFS_DAM_name);
	  dam_proc.slink := 0;
	  unitable^[un].dam := dam_proc.dam;
	  tm_proc.value := value(HFS_TM_name);
	  tm_proc.slink := 0;
	  unitable^[un].tm := tm_proc.tm;
	end;
d512 1
d620 1
a620 1
	    call(init_unit_proc, un, true)
d627 1
a627 1
	    auto_install_HFS(un);
d1010 1
a1010 1
	  auto_install_HFS(lunit);
@


3.8
log
@Pws2unix automatic delta on Tue Sep 30 13:50:02 MEZ 1986
@
text
@@


3.7
log
@Version with LIF primary and UCSD secondary no longer
called "lifversion"; now called "ucsdversion".

@
text
@d631 1
a631 1
	  if tbl[un].is_hfsunit then
d637 1
@


3.6
log
@set_base_unums not quite right.  Also, remove extra ";".
@
text
@a58 1
    lifversion  = 1;    { LIF primary DAM, UCSD secondary }
d60 1
d652 1
a652 1
$if thisversion = lifversion$
@


3.5
log
@ucsdversion (WS1.0 primary, LIF secondary) dropped.
HFS disks now take 1 unit only; used to take same number of
units regardless of DAM.
If HFS, sets system volume to /WORKSTATIONS/SYSTEMxxx
(or /WORKSTATIONS/SYSTEMxxxxxxx), depending on what we booted.
For 1-unit change, added extra arg to tea_* -- physical disk size.
@
text
@d620 1
a620 1
	    call(init_unit_proc, un, true);
d1025 2
a1026 3
		{ both HFS? }
		if tbl[i].is_hfsunit
		and tbl[j].is_hfsunit
@


3.4
log
@HFS sysunit now #46 if can find /WORKSTATIONS/SYSTEM dir.
@
text
@d53 1
a53 1
{set "beta" to true to get CTBETA changes}
d57 1
a57 1
{three possible versions of TABLE}
d59 2
a60 3
    lifversion  = 1;    { no HFS; LIF primary DAM, UCSD secondary }
    ucsdversion = 2;    { no HFS; UCSD primary DAM, LIF secondary }
    hfsversion  = 3;    { with HFS; LIF primary DAM, HFS secondary }
d311 1
a312 1

a328 3
$if thisversion = hfsversion$
  function has_HFS_dam(un: unitnum): boolean;
  procedure make_HFS_unit(un: unitnum);
d330 1
a330 1
$end$
d351 2
a352 1
  procedure tea_CS80_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;os,id,mb:integer);
a436 62
$if thisversion = hfsversion$

{ does this unit have hfsdam as its dam? }
function has_HFS_dam(un: unitnum): boolean;
  var dam_proc:
     packed record case integer of
       0: (dam: damtype);
       1: (value, slink: integer);
     end;
  begin
     dam_proc.dam := unitable^[un].dam;
     has_HFS_dam := (dam_proc.value = value(HFS_DAM_name));
  end;


{ turn this unit into an HFS unit }
procedure make_HFS_unit(un: unitnum);
  var
    dam_proc:
      packed record case integer of
	0: (dam: damtype);
	1: (value, slink: integer);
      end;

    tm_proc:
      packed record case integer of
	0: (tm: amtype);
	1: (value, slink: integer);
      end;
    next_un: unitnum;
  begin
    { assign HFS dam and TM }
    dam_proc.value := value(HFS_DAM_name);
    dam_proc.slink := 0;

    tm_proc.value := value(HFS_TM_name);
    tm_proc.slink := 0;

    with unitable^[un] do begin
	dam := dam_proc.dam;
	tm := tm_proc.tm;
	if letter <> 'R' then
	    byteoffset := 0;
    end;

    { HFS will take up entire disc }
    next_un := un + 1;
    with unitable^[un] do begin
      while (next_un <= maxunit) do begin
	if on_same_medium(un, next_un)
	and (unitable^[next_un].byteoffset = byteoffset+umaxbytes) then
	  begin
	    umaxbytes := umaxbytes+unitable^[next_un].umaxbytes;
	    zap_assigned_unit(next_un);
	  end;
	next_un := next_un + 1;
      end;  {while}
      uvid := '';
    end;

  end;

a480 1
$end$
d482 34
d540 2
a541 1
      p_umaxbytes: integer  );     {volume size in bytes}
d556 9
d568 4
d614 25
a657 6
$if thisversion = ucsdversion$
      primary_dam:
	dam := UCSD_DAM_name;
      secondary_dam:
	dam := LIF_DAM_name;
$end$
d782 1
a782 1
    tea(un,NO_DAM_name,NULL_TM_name,0,0,0,0,0,0,'',#0,F,F,F,0);
d788 1
a788 1
    tea(0,dam(ds),NULL_TM_name,0,0,0,0,0,0,'',RAM,F,T,T,0);
d794 1
a794 1
    tea(un,UNBLOCKED_DAM_name,CRT_TM_name,0,0,0,0,0,0,'CONSOLE',#0,T,T,F,0);
d800 1
a800 1
    tea(un,UNBLOCKED_DAM_name,KBD_TM_name,0,0,0,0,0,0,'SYSTERM',#0,F,T,F,0);
d807 2
a808 1
    tea(un,dam(ds),MINI_TM_name,0,0,du,0,0,0,'',INTERNAL,F,F,T,svol_bytes(INTERNAL));
d814 1
a814 1
    tea(un,BOOT_DAM_name,BOOT_TM_name,0,0,0,0,0,0,'',#0,F,F,T,maxint);
d823 1
a823 1
    tea(un,SRM_DAM_name,SRM_TM_name,sc,ba,du,0,0,0,'',SRM,F,T,T,maxint);
d832 2
a833 1
    tea(un,UNBLOCKED_DAM_name,PRINTER_TM_name,sc,ba,0,0,0,bto,uvid,#0,F,T,F,0);
d845 2
a846 1
    tea(un,dam(ds),F9885_TM_name,sc,0,du,0,os,0,'',HP9885,F,F,T,svol_bytes(HP9885)-os);
d859 2
a860 1
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,0,os,0,'',HP9895,F,F,T,svol_bytes(HP9895)-os);
d869 2
a870 1
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,0,0,0,'',HP8290X,F,F,T,svol_bytes(HP8290X));
d892 1
a892 1
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,0,os,0,'',lr,F,T,T,mb);
d912 1
a912 1
    tea(un,dam(ds),AMIGO_TM_name,sc,ba,du,dv,os,0,'',lr,F,T,T,mb);
d917 2
a918 1
procedure tea_CS80_mv(un:unitnum;ds:ds_type;sc,ba,du,dv:shortint;os,id,mb:integer);
d930 1
a930 1
    tea(un,dam(ds),CS80_TM_name,sc,ba,du,dv,os,id,'',CS80,F,F,T,mb);
d949 1
a949 1
    tea(un,dam(ds),CS80_TM_name,sc,ba,du,dv,0,-1,'',CS80,F,F,T,0);
d971 1
a971 1
    tea(un,dam(ds),BUBBLE_TM_name,sc,0,0,0,0,0,'',BUBBLE,F,T,T,0);
d978 1
a978 1
    tea(un,dam(ds),EPROM_TM_name,0,0,0,sn,0,0,'',EPROM,F,T,T,0);
d1006 4
a1009 1
	end; {with}
d1012 22
d1038 1
d1044 1
d1644 37
d1689 3
d1795 1
d1797 1
a1797 1
		if increment_and_test_lun then
d1811 1
d1813 1
a1813 1
		  if increment_and_test_lun then
d1833 1
d1835 1
a1835 1
		  if increment_and_test_lun then
d1839 2
a1840 1
				     vol_bytes(i, nvols, mp));
d2022 2
a2023 1
			vol_bytes(i, nvols, mp));
d2064 3
a2117 1
$if thisversion = hfsversion$
a2120 29
      { initialize cache and h_unitable }
      call(init_cache_proc);

      { some units have HFSDAM already -- init them }
      for i := 0 to maxunit do begin
	  if has_HFS_dam(i) and not tbl[i].is_hfsunit then begin
	      call(init_unit_proc, i, true);
	      make_HFS_unit(i);
	  end;
      end;

      { autoconfigure -- all hard discs with superblock become HFS }
      { also any RAM volume with superblock }
      for i := 1 to maxunit do begin
	  if (unitable^[i].letter = 'R') or
	  ((first_harddisc_lun <= i) and (i <= last_harddisc_lun)) then
	      { HFS disc must be at beginning of disc }
	      if (unitable^[i].letter <> #0) and
	      not on_same_medium(i, i-1) then begin
		  call(init_unit_proc, i, false);
		  { init_unit_proc sets is_hfsunit if superblock there }
		  if tbl[i].is_hfsunit then
		      make_HFS_unit(i);
	      end;
      end;

      { must call configure_cache after looking at the units }
      call(config_cache_proc);

d2122 1
a2122 1
      { also, try to set sysvolume to #46:/WORKSTATIONS/SYSTEM  }
d2125 3
a2127 1
	extra_HFS_unit(sysunit, 46, sysprefix);
d2145 1
a2145 1
$end$
a2148 1

@


3.3
log
@Allow HFS memory volumes, too.  These are checked for a
superblock just as hard disks are.
@
text
@d24 1
d2069 7
a2075 10
      { if sysunit is HFS, need to reset syvid and dkvid        }
      { also, try to prefix to sysprefix (/WORKSTATIONS/SYSTEM) }
      if tbl[sysunit].is_hfsunit then begin
	if sysunit_ok(sysunit) then
	  if unit_prefix_successful(syvid+':'+sysprefix) then begin
	    syvid := unitable^[sysunit].uvid;
	    extra_HFS_unit(sysunit, sysunit+1, '/');
	    if unitable^[sysunit+1].uvid <> '' then
	      dkvid := unitable^[sysunit+1].uvid;
	  end;
a2091 1

d2095 1
@


3.2
log
@If sysunit is HFS, add another unit on same volume and put dkvid
there, sort of like on the SRM.
@
text
@d480 2
a481 1
	byteoffset := 0;
d2051 12
a2062 9
      for i := first_harddisc_lun to last_harddisc_lun do begin
	  { HFS disc must be at beginning of disc }
	  if (unitable^[i].letter <> #0) and
	  not on_same_medium(i, i-1) then begin
	      call(init_unit_proc, i, false);
	      { init_unit_proc sets is_hfsunit if superblock there }
	      if tbl[i].is_hfsunit then
		  make_HFS_unit(i);
	  end;
@


3.1
log
@Automatic bump of revision number for PWS version 3.2h
@
text
@d2068 1
a2068 1
	  if unit_prefix_successful(syvid+':'+sysprefix) then
d2070 4
d2076 4
a2079 2
      { At this point, there is only one HFS unit per disc.  Add more }
      { as follows:                                                   }
@


2.5
log
@Bug in make_HFS_unit: assumed other LIF units on same disc were
numbered sequentially.  
@
text
@@


2.4
log
@Add routine that adds extra HFS units on existing HFS discs.
If sysunit is HFS, prefix to /WORKSTATIONS/SYSTEM if possible.
Default CTABLE version now hfsversion, not lifversion.
@
text
@d486 3
a488 2
      while (next_un <= maxunit) and on_same_medium(un, next_un) do begin
	if unitable^[next_un].byteoffset = byteoffset+umaxbytes then
@


2.3
log
@If sysunit HFS, reset syvid and dkvid by calling sysunit_ok.
@
text
@d64 1
a64 1
    thisversion = lifversion;
d247 1
a247 1
  sysglobals, loader, options, ldr;
d332 1
d440 1
d498 45
d544 1
d1351 1
a1351 1
  srmsysprefix = '/WORKSTATIONS/SYSTEM';
d1990 2
a1991 2
  if not unit_prefix_successful('#45:'+srmsysprefix+srmnode(unitable^[45].sc)) then
    if not unit_prefix_successful('#45:'+srmsysprefix) then
a2059 1

d2063 17
a2079 3
      { if sysunit is HFS, need to reset syvid and dkvid }
      if tbl[sysunit].is_hfsunit then
	  ok := sysunit_ok(sysunit);
@


2.2
log
@Set uvid of HFS discs to ''; next getvolumename corrects this.
@
text
@d2015 5
@


2.1
log
@Auto bump rev number to 2.1 for sys 3.2e.
@
text
@d483 1
a483 1
    with unitable^[un] do
d492 2
d2003 2
a2004 1
	  if not on_same_medium(i, i-1) then begin
@


1.5
log
@Fix bug where hfsversion had pri/sec as HFS/LIF instead
of LIF/HFS.

@
text
@@


1.4
log
@Call init_unit_proc with new 2nd parameter, now in GLOBALS and hfscache.
@
text
@d58 1
a58 1
    hfsversion  = 1;    { with HFS; LIF primary DAM, UCSD secondary }
d60 1
a60 1
    lifversion  = 3;    { no HFS; LIF primary DAM, UCSD secondary }
d588 2
a590 2
      secondary_dam:
	dam := LIF_DAM_name;
@


1.3
log
@Set defaults to old ones: not CTBETA version, and LIF/UCSD dams as
primary/secondary (thisversion = lifversion).
@
text
@d1993 1
a1993 1
	      call(init_unit_proc, i{, true});
d2002 1
a2002 1
	      call(init_unit_proc, i{, false});
@


1.2
log
@This source now includes, selectable by conditional compilation,
the old CTBETA version.  It also allows parametric selection of HFS, and of the primary/secondary
DAM pairs LIF/UCSD (lifversion), UCSD/LIF (ucsdversion),
and LIF/HFS (hfsversion).
@
text
@d54 1
a54 1
    beta = true;
d64 1
a64 1
    thisversion = hfsversion;
@


1.1
log
@Initial revision
@
text
@d52 14
a71 9
{local mass storage directory access method}
  type
    lms_dam_type = {local mass storage dam}
      ( LIF, UCSD );
  const
    primary_lms_dam =
      LIF;


d184 1
d193 1
d259 1
d264 1
d305 2
a306 1
	UCSD_dam  );     {UCSD, regardless of primary/secondary choice}
d329 4
d349 1
d351 1
d372 1
d386 1
d437 58
d586 1
d588 1
a588 3
	if primary_lms_dam=LIF
	  then dam := LIF_DAM_name
	  else dam := UCSD_DAM_name;
d590 16
a605 3
	if primary_lms_dam=LIF
	  then dam := UCSD_DAM_name
	  else dam := LIF_DAM_name;
d623 1
d628 1
d641 1
d646 1
d661 1
d666 1
d822 4
d827 1
d837 1
d855 1
d1094 4
d1099 1
d1116 4
d1121 1
d1368 4
d1373 1
d1516 4
d1521 1
d1620 1
a1620 1
  { standard assignemnts: avoid changing }
d1645 1
a1645 1
  $if true$
d1658 4
d1663 1
d1676 1
d1694 1
d1719 1
a1719 1
  $end$  { local hard discs }
d1724 1
a1724 1
  $if true$
d1734 1
a1734 1
  $end$  { CS80 tapes }
d1820 1
d1876 1
d1983 31
@
