*BSD News Article 49626


Return to BSD News archive

Newsgroups: comp.bugs.2bsd
Path: euryale.cc.adfa.oz.au!newshost.anu.edu.au!harbinger.cc.monash.edu.au!simtel!news.sprintlink.net!in1.uu.net!spcuna!wlbr!sms
From: sms@wlv.iipo.gtegsc.com (Steven M. Schultz)
Subject: SMD (xp driver) disklabel capability added (#271)
Sender: news@wlbr.iipo.gtegsc.com (System Administrator)
Organization: GTE Government Systems, Westlake Village
Message-ID: <DDr51K.Ipn@wlbr.iipo.gtegsc.com>
X-Nntp-Posting-Host: wlv.iipo.gtegsc.com
Date: Wed, 23 Aug 1995 07:05:43 GMT
Lines: 2769

Subject: SMD (xp driver) disklabel capability added (#271)
Index:	sys/{pdpuba,pdpstand,conf}/xp.c,conf.c,...  2.11BSD

Description:
	The SMD (xp) driver which handles RM04,5,6, RM02,3,5, Fuji-160
	and many other SMD drives has been updated to be disklabel
	capable.

Repeat-By:
	N/A

Fix:
	All previous updates (*especially* 250 - 267)  thru 270 must
	have been applied to the system.

	Cut where indicated and save to a file (/tmp/271).  Then:

		patch -p0 < /tmp/271

	and follow the directions in #250.  The instructions in update #250
	are not repeated here but are available (as are all 2.11BSD updates)
	via anonymous ftp to the host FTP.IIPO.GTEGSC.COM in the directory
	/pub/2.11BSD.

	NOTE:  If you do not have any SMD drives present in the system then
	       all you need to do is recompile and install the 'boot' program.
=====================cut here=================
*** /usr/src/sys/pdpuba/hpreg.h.old	Thu Jul  1 19:52:33 1993
--- /usr/src/sys/pdpuba/hpreg.h	Thu Jul 20 19:48:12 1995
***************
*** 3,82 ****
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)hpreg.h	1.1 (2.10BSD Berkeley) 12/1/86
   */
  
  /*
!  * Definitions for SMD-type disk drives and drivers.  That includes
!  * RM02/03/05's, RP04/05/06's, and everything using the XP driver.
!  * Also added RP07. /BQT 930612
   */
  
! /*
!  * Defines for disk drive type registers
!  */
! #define	RP04	020		/* RP04 */
! #define	RP05	021		/* RP05 */
! #define	RP06	022		/* RP06 */
! #define RP07	042		/* RP07 */
! #define	RM03	024		/* RM03 */
! #define	RM02	025		/* RM02 */
! #define	RM05	027		/* RM05 or SI 9500, CDC 9766 */
! /*
!  * These drive types are dummies because the actual numbers conflict
!  * with DEC controllers.  The RM5X and the RM2X actually read as 25; the
!  * Diva Comp VI reads as 22.  Xp_drive must be patched at boot time or
!  * initialized.
!  */
! #define	CAP	072		/* Ampex Capricorn */
! #define	SI5	073		/* SI, CDC 9775 Direct */
! #define	SI	074		/* SI 6100, Fuji Eagle 2351A */
! #define	RM2X	075		/* Emulex SC01B or SI 9400, Fuji 160 */
! #define	RM5X	076		/* Emulex SC-21, Ampex 815 cylider RM05 */
! #define	DV	077		/* Diva Comp V, Ampex 9300 */
  
- #define	HP_SECT		22	/* RP04/05/06 */
- #define	HP_TRAC		19
- #define	RP04_CYL	411	/* RP04/05 */
- #define	RP06_CYL	815	/* RP06 */
- 
- #define RP7_SECT	50	/* DEC RP07 */
- #define RP7_TRAC	32
- #define RP7_CYL		630
- 
- #define	RM_SECT		32	/* RM02/03 */
- #define	RM_TRAC		5
- #define	RM_CYL		823
- 
- #define	RM5_SECT	32	/* RM05, CDC 9766 */
- #define	RM5_TRAC	19
- #define	RM5_CYL		823
- 
- #define	CAP_SECT	32	/* Ampex Capricorn */
- #define	CAP_TRAC	16
- #define	CAP_CYL		1024
- 
- #define	SI5_SECT	32	/* SI, CDC 9775 direct */
- #define SI5_TRAC	40
- #define SI5_CYL		843
- 
- #define	SI_SECT		48	/* SI 6100, Fuji Eagle 2351A */
- #define	SI_TRAC		20
- #define	SI_CYL		842
- 
- #define	RM2X_SECT	32	/* Emulex SC01B or SI 9400, Fuji 160 */
- #define	RM2X_TRAC	10
- #define	RM2X_CYL	823
- 
- #define	RM5X_SECT	32	/* Emulex, Ampex 815 cylider RM05 */
- #define	RM5X_TRAC	19
- #define	RM5X_CYL	815
- 
- #define	DV_SECT		33	/* Diva Comp V, Ampex 9300 */
- #define	DV_TRAC		19
- #define	DV_CYL		815
- 
- 
  /*
   *	Controller registers and bits
   */
--- 3,20 ----
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)hpreg.h	2.0 (2.11BSD) 1995/07/20
   */
  
  /*
!  * Definitions for SMD-type disk drives and drivers.
   */
  
! #define	XP_CC	0x1	/* drivedata[0] bit indicating presence of current
! 			 * cylinder 'hpcc' register.  Only set for RP04,5,6,7.
! 			*/
! #define	XP_NOSEARCH 0x2	/* drivedata[0] bit indicating lack of search cmd */
  
  /*
   *	Controller registers and bits
   */
***************
*** 104,110 ****
  	short	hpof;		/* offset register */
  	short	hpdc;		/* desired cylinder address register */
  	short	hpcc;		/* HP: current cylinder register */
! #define	rmhr	hpcc;		/* RM: holding register */
  	short	hper2;		/* HP: error register 2 */
  #define	rmmr2	hper2		/* RM: maintenance register 2 */
  	short	hper3;		/* HP: error register 3 */
--- 42,48 ----
  	short	hpof;		/* offset register */
  	short	hpdc;		/* desired cylinder address register */
  	short	hpcc;		/* HP: current cylinder register */
! #define	rmhr	hpcc		/* RM: holding register */
  	short	hper2;		/* HP: error register 2 */
  #define	rmmr2	hper2		/* RM: maintenance register 2 */
  	short	hper3;		/* HP: error register 3 */
***************
*** 131,136 ****
--- 69,75 ----
  
  /* commands */
  #define	HP_NOP		000
+ #define	HP_UNLOAD	002		/* offline drive */
  #define	HP_SEEK		004		/* seek */
  #define	HP_RECAL	006		/* recalibrate */
  #define	HP_DCLR		010		/* drive clear */
***************
*** 220,229 ****
  #define	HPDT_DRR	0004000		/* drive request required  */
  /* bits 10-9 are unused */
  /* bits 8-0 are drive type; the correct values are hard to determine */
- #define	HPDT_RM05SP	0000047		/* single ported rm05 */
- #define	HPDT_RM05DP	0000027		/* dual ported rm05 */
  #define	HPDT_RM02	0000025		/* rm02, possibly rm03? */
  #define	HPDT_RM03	0000024		/* rm03 */
  #define	HPDT_RP06	0000022		/* rp06 */
  #define HPDT_RP07	0000042		/* rp07 */
  
--- 159,170 ----
  #define	HPDT_DRR	0004000		/* drive request required  */
  /* bits 10-9 are unused */
  /* bits 8-0 are drive type; the correct values are hard to determine */
  #define	HPDT_RM02	0000025		/* rm02, possibly rm03? */
+ #define	HPDT_RM80	0000026		/* rm80 */
+ #define	HPDT_RM05	0000027		/* rm05 */
  #define	HPDT_RM03	0000024		/* rm03 */
+ #define	HPDT_RP04	0000020		/* rp04 */
+ #define	HPDT_RP05	0000021		/* rp05 */
  #define	HPDT_RP06	0000022		/* rp06 */
  #define HPDT_RP07	0000042		/* rp07 */
  
***************
*** 243,248 ****
--- 184,199 ----
  #define	HPOF_BITS	\
  "\10\15FMT22\14ECI\13HCI\10OD"
  
+ /*
+  * rmhr
+  *
+  * Emulex (i.e non DEC) controllers implement the ability to query for
+  * the drive geometry by placing these codes into the 'holding register'.
+ */
+ #define	HPHR_MAXCYL	0x8017		/* max cylinder */
+ #define	HPHR_MAXTRAK	0x8018		/* max track/cylinder */
+ #define	HPHR_MAXSECT	0x8019		/* max sector/track */
+ 
  /* rmer2: These are the bits for an RM error register 2 */
  #define	RMER2_BSE	0100000		/* bad sector error */
  #define	RMER2_SKI	0040000		/* seek incomplete */
***************
*** 279,285 ****
  #define	SIMB_MB	0xff00		/* model byte value */
  #define	SIMB_S6	0x2000		/* switch s6 */
  #define	SIMB_LU	0x0007		/* logical unit (should = drive #) */
- #define	SIMB_XX	0x4000		/* for some reason this is sometimes set */
  
  #define	SI9775D	0x0700		/* 9775 direct */
  #define	SI9775M	0x0e00		/* 9775 mapped */
--- 230,235 ----
*** /usr/src/sys/pdpuba/xp.c.old	Thu Apr 13 22:41:12 1995
--- /usr/src/sys/pdpuba/xp.c	Mon Aug 21 21:08:34 1995
***************
*** 3,21 ****
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)xp.c	1.8 (2.11BSD GTE) 1995/04/13
   */
  
  /*
!  * RM02/03/05, RP04/05/06, Ampex 9300, CDC 9766, DIVA, Fuji 160, and SI
!  * Eagle.  This driver will handle most variants of SMD drives on one or more
!  * controllers.  If XP_PROBE is defined, it includes a probe routine that
!  * will determine the number and type of drives attached to each controller;
!  * otherwise, the data structures must be initialized.
!  * Added RP07.  /BQT 930612
!  *
!  * For simplicity we use hpreg.h instead of an xpreg.h.
!  * The bits are the same.
   */
  
  #include "xp.h"
--- 3,14 ----
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)xp.c	2.2 (2.11BSD GTE) 1995/08/21
   */
  
  /*
!  * RM02/03/05, RP04/05/06/07, CDC 9766, SI, Fuji 160 and Eagle.  This
!  * driver will handle most variants of SMD drives on one or more controllers.
   */
  
  #include "xp.h"
***************
*** 33,45 ****
  #include "dk.h"
  #include "disklabel.h"
  #include "disk.h"
  #include "map.h"
  #include "uba.h"
  
  #define	XP_SDIST	2
  #define	XP_RDIST	6
- #define	xpunit(dev)	((minor(dev) >> 3) & 07)
  
  int xp_offset[] = {
  	HPOF_P400,	HPOF_M400,	HPOF_P400,	HPOF_M400,
  	HPOF_P800,	HPOF_M800,	HPOF_P800,	HPOF_M800,
--- 26,52 ----
  #include "dk.h"
  #include "disklabel.h"
  #include "disk.h"
+ #include "file.h"
  #include "map.h"
  #include "uba.h"
+ #include "stat.h"
+ #include "syslog.h"
  
  #define	XP_SDIST	2
  #define	XP_RDIST	6
  
+ /*
+  * 'xp' is unique amoung 2.11BSD disk drivers.  Drives are not organized
+  * into groups of 8 drives per controller.  Instead drives are numbered
+  * across controllers:  the second drive ("unit 1") could be on the 2nd
+  * controller.  This has the effect of turning the high 5 bits of the minor
+  * device number into the unit number and drives are thus numbered 0 thru 31.
+  *
+  * NOTE: this  is different than /boot's view of the world.  Sigh.
+ */
+ 
+ #define	XPUNIT(dev)	((minor(dev) >> 3) & 0x1f)
+ 
  int xp_offset[] = {
  	HPOF_P400,	HPOF_M400,	HPOF_P400,	HPOF_M400,
  	HPOF_P800,	HPOF_M800,	HPOF_P800,	HPOF_M800,
***************
*** 51,287 ****
  	struct	buf *xp_actf;		/* pointer to next active xputab */
  	struct	buf *xp_actl;		/* pointer to last active xputab */
  	struct	hpdevice *xp_addr;	/* csr address */
! 	char	xp_flags;		/* controller-type flags */
  	char	xp_active;		/* nonzero if doing a transfer */
  };
  
  struct xp_drive {
  	struct	xp_controller *xp_ctlr; /* controller to which slave attached */
! 	char	xp_type;		/* drive type */
! 	char	xp_unit;		/* slave number */
! 	struct	size *xp_sizes;		/* pointer to sizes array */
! 	char	xp_nsect;
! 	char	xp_ntrack;
! 	int	xp_nspc;		/* sectors/cylinder */
! 	int	xp_cc;			/* current cylinder, for RM's */
! #ifdef BADSECT
! 	int	xp_ncyl;		/* cylinders per pack */
! #endif
! };
! 
  /*
!  * bits in xp_flags:
!  */
! #define	XP_NOCC		1		/* has no current cylinder register */
! #define	XP_RH70		2		/* uses 22-bit addressing */
! #define	XP_NOSEARCH	4		/* won't do search commands */
  
! #ifdef BADSECT
! #define	NCYL(x)		(x)
! #else !BADSECT
! #define	NCYL(x)		/* not used */
! #endif BADSECT
  
- #ifndef XP_PROBE
- /*
-  * Macros to inititialize xp_drive entries.  These can be used as examples,
-  * or as the actual initializers in ioconf.c.  The arguments are the number
-  * of the controller to which the drive is attached, and the physical
-  * drive unit number.  Used only if XP_PROBE is not defined.  See xp.c
-  * for more information.
-  */
- #define	RM02_INIT(c,u) \
- 	{ &xp_controller[c], RM02, u, &rm_sizes, \
- 	RM_SECT, RM_TRAC, RM_SECT*RM_TRAC, 0, NCYL(RM_CYL)  } 
- #define	RM03_INIT(c,u) \
- 	{ &xp_controller[c], RM03, u, &rm_sizes, \
- 	RM_SECT, RM_TRAC, RM_SECT*RM_TRAC, 0, NCYL(RM_CYL)  } 
- #define	RM05_INIT(c,u) \
- 	{ &xp_controller[c], RM05, u, &rm5_sizes, \
- 	RM5_SECT, RM5_TRAC, RM5_SECT*RM5_TRAC, 0, NCYL(RM5_CYL)  } 
- #define	RM05X_INIT(c,u) \
- 	{ &xp_controller[c], RM05X, u, &rm5_sizes, \
- 	RM5_SECT, RM5_TRAC, RM5_SECT*RM5_TRAC, 0, NCYL(RM5X_CYL)  } 
- #define	RP06_INIT(c,u) \
- 	{ &xp_controller[c], RP06, u, &hp_sizes, \
- 	HP_SECT, HP_TRAC, HP_SECT*HP_TRAC, 0, NCYL(RP06_CYL)  } 
- #define	RP05_INIT(c,u) \
- 	{ &xp_controller[c], RP05, u, &hp_sizes, \
- 	HP_SECT, HP_TRAC, HP_SECT*HP_TRAC, 0, NCYL(RP04_CYL)  } 
- #define	RP04_INIT(c,u) \
- 	{ &xp_controller[c], RP04, u, &hp_sizes, \
- 	HP_SECT, HP_TRAC, HP_SECT*HP_TRAC, 0, NCYL(RP04_CYL)  } 
- #define	SI_INIT(c,u) \
- 	{ &xp_controller[c], SI, u, &si_sizes, \
- 	SI_SECT, SI_TRAC, SI_SECT*SI_TRAC, 0, NCYL(SI_CYL)  }
- #define	DV_INIT(c,u) \
- 	{ &xp_controller[c], DV, u, &dv_sizes, \
- 	DV_SECT, DV_TRAC, DV_SECT*DV_TRAC, 0, NCYL(DV_CYL)  } 
- #define	RM2X_INIT(c,u) \
- 	{ &xp_controller[c], RM2X, u, &rm2x_sizes, \
- 	RM2X_SECT, RM2X_TRAC, RM2X_SECT*RM2X_TRAC, 0, NCYL(RM2X_CYL)  }
- #endif !XP_PROBE
- 
- 
- /*
-  * xp_drive and xp_controller may be initialized here, or filled in at boot
-  * time if XP_PROBE is enabled.  xp_controller address fields must be
-  * initialized for any boot devices, however.
-  *
-  * xp_controller structure: one line per controller.  Only the address need
-  * be initialized in the controller structure if XP_PROBE is defined (at least
-  * the address for the root device); otherwise the flags must be here also.
-  * The XP_NOCC flag is set for RM02/03/05's (with no current cylinder
-  * register); XP_NOSEARCH is set for Diva's without the search command.  The
-  * XP_RH70 flag need not be set here, the driver will always check that.
-  */
- #define XPADDR	((struct hpdevice *)0176700)
- 
- struct xp_controller	xp_controller[NXPC] = {
- /*	0	0	addr	flags			0 */
- #ifdef XP_PROBE
- 	0,	0,	XPADDR,	0,			0
- #else
- 	0,	0,	XPADDR,	XP_NOCC|XP_NOSEARCH,	0
- #endif
- };
- 
- /*
-  * xp_drive structure: one entry per drive.  The drive structure must be
-  * initialized if XP_PROBE is not enabled.  Macros are provided in hpreg.h
-  * to initialize entries according to drive type, and controller and drive
-  * numbers.  See those for examples on how to set up other types of drives.
-  * With XP_PROBE defined, xpslave will fill in this structure, and any
-  * initialization will be overridden.  There is one exception; if the
-  * drive-type field is set, it will be used instead of the drive-type register
-  * to determine the drive's type.
-  */
- struct xp_drive	xp_drive[NXPD]
- #ifndef XP_PROBE
- = {
- 	RM02_INIT(0,0),		/* RM02, controller 0, drive 0 */
- 	RM02_INIT(0,1),		/* RM02, controller 0, drive 1 */
- 	RM2X_INIT(0,0)		/* Fuji 160, controller 0, drive 0 */
- 	RM2X_INIT(0,1)		/* Fuji 160, controller 0, drive 1 */
- 	RM05X_INIT(0,2)		/* 815-cyl RM05, controller 0, drive 2 */
- }
- #endif
- ;
- 
- /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
- struct size {
- 	daddr_t	nblocks;
- 	int	cyloff;
- } hp_sizes[8] = { /* RP04/05/06 */
- 	   9614,	  0,	/* a: cyl   0 - 22 */
- 	   8778,	 23,	/* b: cyl  23 - 43 */
- 	 153406,	 44,	/* c: cyl  44 - 410, RP04/05 */
- 	 168872,	411,	/* d: cyl 411 - 814, RP06 */
- 	 322278,	 44,	/* e: cyl  44 - 814, RP06 */
- 	      0,	  0,	/* f: Not Defined */
- 	 171798,	  0,	/* g: cyl   0 - 410, whole RP04/05 */
- 	 340670,	  0,	/* h: cyl   0 - 814, whole RP06 */
- }, rp_sizes[8] = { /* RP07 */
- 	  19200,	  0,	/* a: cyl   0 - 11 */
- 	  51200,	 12,	/* b: cyl  12 - 43 */
- 	1008000,	  0,	/* c: cyl   0 - 629, whole RP07 */
- 	 320000,	 44,	/* d: cyl  44 - 243 */
- 	 320000,	244,	/* e: cyl 244 - 443 */
- 	 297600,	444,	/* f: cyl 444 - 629 */
- 	 937600,	 44,	/* g: cyl  44 - 629 */
- 	1008000,	  0,	/* h: cyl   0 - 629, whole RP07 */
- }, rm_sizes[8] = { /* RM02/03 */
- 	   9600,	  0,	/* a: cyl   0 -  59 */
- 	   9600,	 60,	/* b: cyl  60 - 119 */
- 	 131680,	  0,	/* c: cyl   0 - 822, whole RM02/03 */
- 	      0,	  0,	/* d: Not Defined */
- 	      0,	  0,	/* e: Not Defined */
- 	 121920,	 60,	/* f: cyl  60 - 821 */
- 	 112320,	120,	/* g: cyl 120 - 821 */
- 	 131680,	  0,	/* h: cyl   0 - 822, whole RM02/03 */
- }, rm5_sizes[8] = { /* RM05, or SI 9500, CDC 9766 */
- 	   9120,	  0,	/* a: cyl   0 -  14 */
- 	   9120,	 15,	/* b: cyl  15 -  29 */
- 	 234080,	 30,	/* c: cyl  30 - 414 */
- 	 248064,	415,	/* d: cyl 415 - 822 */
- 	 164160,	 30,	/* e: cyl  30 - 299 */
- 	 152000,	300,	/* f: cyl 300 - 549 */
- 	 165984,	550,	/* g: cyl 550 - 822 */
- 	 500384,	  0,	/* h: cyl   0 - 822 */
- }, cap_sizes[8] = { /* Ampex Capricorn */
- 	  16384,	  0,	/* a: cyl   0 thru   31 */
- 	  33792,	 32,	/* b: cyl  32 thru   97 */
- 	 291840,	 98,	/* c: cyl  98 thru  667 */
- 	  16384,	668,	/* d: cyl 668 thru  699 */
- 	  56320,	700,	/* e: cyl 700 thru  809 */
- 	 109568,	810,	/* f: cyl 810 thru 1023 */
- 	 182272,	668,	/* g: cyl 668 thru 1023 */
- 	 524288,	  0,	/* h: cyl   0 thru 1023 */
- }, si5_sizes[8] = { /* SI, CDC 9775, direct mapping */
- 	  10240,	  0,	/* a: cyl   0 -   7 */
- 	  10240,	  8,	/* b: cyl   8 -  15 */
- 	 510720,	 16,	/* c: cyl  16 - 414 */
- 	 547840,	415,	/* d: cyl 415 - 842 */
- 	 363520,	 16,	/* e: cyl  16 - 299 */
- 	 320000,	300,	/* f: cyl 300 - 549 */
- 	 375040,	550,	/* g: cyl 550 - 842 */
- 	1079040,	  0,	/* h: cyl   0 - 842 */
- }, si_sizes[8] = { /* SI 6100, Fuji Eagle 2351A */
- 	  11520,	  0,	/* a: cyl   0 -  11 */
- 	  11520,	 12,	/* b: cyl  12 -  23 */
- 	 474240,	 24,	/* c: cyl  24 - 517 */
- 	  92160,	518,	/* d: cyl 518 - 613 */
- 	 218880,	614,	/* e: cyl 614 - 841 */
- 	      0,	  0,	/* f: Not Defined */
- 	      0,	  0,	/* g: Not Defined */
- 	 808320,	  0,	/* h: cyl   0 - 841 (everything) */
- }, rm2x_sizes[8] = { /* Emulex SC01B or SI 9400, Fuji 160 */
- 	   9600,	  0,	/* a: cyl   0 -  29 */
- 	   9600,	 30,	/* b: cyl  30 -  59 */
- 	 244160,	 60,	/* c: cyl  60 - 822 */
- 	 164800,	 60,	/* d: cyl  60 - 574 */
- 	  79360,	575,	/* e: cyl 575 - 822 */
- 	  39680,	575,	/* f: cyl 575 - 698 */
- 	  39680,	699,	/* g: cyl 699 - 822 */
- 	 263360,	  0,	/* h: cyl   0 - 822 */
- }, dv_sizes[8] = { /* Diva Comp V, Ampex 9300 in direct mode */
- 	   9405,	  0,	/* a: cyl   0 -  14 */
- 	   9405,	 15,	/* b: cyl  15 -  29 */
- 	 241395,	 30,	/* c: cyl  30 - 414 */
- 	 250800,	415,	/* d: cyl 415 - 814 */
- 	 169290,	 30,	/* e: cyl  30 - 299 */
- 	 156750,	300,	/* f: cyl 300 - 549 */
- 	 166155,	550,	/* g: cyl 550 - 814 */
- 	 511005,	  0,	/* h: cyl   0 - 814 */
- };
- /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
- 
- #ifdef XP_PROBE
- struct xpst {
- 	short	type;		/* value from controller type register */
- 	short	nsect;		/* number of sectors/track */
- 	short	ntrack;		/* number of tracks/cylinder */
- 	short	ncyl;		/* number of cylinders */
- 	struct	size *sizes;	/* partition tables */
- 	short	flags;		/* controller flags */
- } xpst[] = {
- 	{ RP04, HP_SECT,   HP_TRAC,   RP04_CYL, hp_sizes,   0 },
- 	{ RP05, HP_SECT,   HP_TRAC,   RP04_CYL, hp_sizes,   0 },
- 	{ RP06, HP_SECT,   HP_TRAC,   RP06_CYL, hp_sizes,   0 },
- 	{ RP07, RP7_SECT,  RP7_TRAC,  RP7_CYL,  rp_sizes,   0 },
- 	{ RM02, RM_SECT,   RM_TRAC,   RM_CYL,   rm_sizes,   XP_NOCC },
- 	{ RM03, RM_SECT,   RM_TRAC,   RM_CYL,   rm_sizes,   XP_NOCC },
- 	{ RM05, RM5_SECT,  RM5_TRAC,  RM5_CYL,  rm5_sizes,  XP_NOCC },
- 	{ CAP,  CAP_SECT,  CAP_TRAC,  CAP_CYL,  cap_sizes,  XP_NOCC },
- 	{ SI5,  SI5_SECT,  SI5_TRAC,  SI5_CYL,  si5_sizes,  XP_NOCC },
- 	{ SI,   SI_SECT,   SI_TRAC,   SI_CYL,   si_sizes,   XP_NOCC },
- 	{ RM2X, RM2X_SECT, RM2X_TRAC, RM2X_CYL, rm2x_sizes, XP_NOCC },
- 	{ RM5X, RM5X_SECT, RM5X_TRAC, RM5X_CYL, rm5_sizes,  XP_NOCC },
- 	{ DV,   DV_SECT,   DV_TRAC,   DV_CYL,	dv_sizes,   XP_NOSEARCH },
- 	{ 0,    0,         0,         0,        0 }
- };
- #endif
- 
  struct	buf	xptab;
  struct	buf	xputab[NXPD];
  
--- 58,91 ----
  	struct	buf *xp_actf;		/* pointer to next active xputab */
  	struct	buf *xp_actl;		/* pointer to last active xputab */
  	struct	hpdevice *xp_addr;	/* csr address */
! 	char	xp_rh70;		/* massbus flag */
  	char	xp_active;		/* nonzero if doing a transfer */
  };
  
  struct xp_drive {
  	struct	xp_controller *xp_ctlr; /* controller to which slave attached */
! 	int	xp_unit;		/* slave number */
! 	u_short	xp_nsect;
! 	u_short	xp_ntrack;
! 	u_short	xp_nspc;		/* sectors/cylinder */
! 	u_short	xp_cc;			/* current cylinder, for RM's */
! 	u_long	xp_dd0;			/* drivedata longword 0 */
! 	struct	dkdevice xp_dk;		/* kernel resident portion of label */
! 	u_short	xp_ncyl;		/* cylinders per pack */
! 	};
  /*
!  * Some shorthand for accessing the in-kernel label structure.
! */
! #define	xp_bopen	xp_dk.dk_bopenmask
! #define	xp_copen	xp_dk.dk_copenmask
! #define	xp_open		xp_dk.dk_openmask
! #define	xp_flags	xp_dk.dk_flags
! #define	xp_label	xp_dk.dk_label
! #define	xp_parts	xp_dk.dk_parts
  
! struct xp_controller	xp_controller[NXPC];
! struct xp_drive	xp_drive[NXPD];
  
  struct	buf	xptab;
  struct	buf	xputab[NXPD];
  
***************
*** 288,294 ****
  #ifdef BADSECT
  struct	dkbad	xpbad[NXPD];
  struct	buf	bxpbuf[NXPD];
- bool_t	xp_init[NXPD];
  #endif
  
  #ifdef UCB_METER
--- 92,97 ----
***************
*** 295,365 ****
  static	int		xp_dkn = -1;	/* number for iostat */
  #endif
  
  /*
!  * Attach controllers whose addresses are known at boot time.  Stop at the
!  * first not found, so that the drive numbering won't get confused.
   */
- xproot()
- {
- 	register int i;
- 	register struct hpdevice *xpaddr;
  
! #ifdef	GENERIC
! 	printf("\nxp_drive=0%o xp_controller=0%o\n",xp_drive,xp_controller);
! 	delay(10000000L);	/* 10 secs to halt and patch xp_drive */
! #endif
! 	for (i = 0; i < NXPC; i++)
! 		if (((xpaddr = xp_controller[i].xp_addr) == 0)
! 			|| (xpattach(xpaddr, i) == 0))
! 			break;
! }
  
  /*
   * Attach controller at xpaddr.  Mark as nonexistent if xpaddr is 0; otherwise
!  * attach slaves if probing.  NOTE: if probing for drives, this routine must
!  * be called once per controller, in ascending controller numbers.
   */
  xpattach(xpaddr, unit)
  	register struct hpdevice *xpaddr;
! 	int unit;
  {
  	register struct xp_controller *xc = &xp_controller[unit];
- #ifdef XP_PROBE
  	static int last_attached = -1;
- #endif
  
  #ifdef UCB_METER
! 	if (xp_dkn < 0) {
  		dk_alloc(&xp_dkn, NXPD+NXPC, "xp", 0L);
- #ifndef XP_PROBE
- 		/*
- 		 * Hard coded drive configuration - snag the number of
- 		 * sectors per track for each drive and compute drive
- 		 * transfer rate assuming 3600rpm (the Fujitsu Eagle 2351A
- 		 * (SI Eagle) is actually 3961rpm; it's just not worth the
- 		 * effort to fix the assumption.)  If XP_PROBE is defined we
- 		 * grab the number of sectors/track for each drive in
- 		 * xpslave.
- 		 */
- 		if (xp_dkn >= 0) {
- 			register int i;
- 			register long *lp;
- 
- 			for (i = 0, lp = &dk_wps[xp_dkn]; i < NXPD; i++)
- 				*lp++ = (long)xp_drive[i].xp_nsect
-  					* (60L * 256L);
- 		}
  #endif
- 	}
- #endif
  
  	if ((unsigned)unit >= NXPC)
  		return(0);
! 	if ((xpaddr != 0) && (fioword(xpaddr) != -1)) {
  		xc->xp_addr = xpaddr;
  		if (fioword(&xpaddr->hpbae) != -1)
! 			xc->xp_flags |= XP_RH70;
! #ifdef XP_PROBE
  	/*
  	 *  If already attached, ignore (don't want to renumber drives)
  	 */
--- 98,158 ----
  static	int		xp_dkn = -1;	/* number for iostat */
  #endif
  
+ 	int	xpstrategy();
+ 	void	xpgetinfo();
+ 	daddr_t	xpsize();
+ extern	size_t	physmem;
+ 
  /*
!  * Setup root SMD ('xp') device (use bootcsr passed from ROMs).  In the event
!  * that the system was not booted from a SMD drive but swapdev is a SMD device
!  * we attach the first (0176700) controller.  This would be a very unusual
!  * configuration and is unlikely to be encountered.
!  *
!  * This is very confusing, it is an ugly hack, but short of moving autoconfig
!  * back into the kernel there's nothing else I can think of to do.
!  *
!  * NOTE:  the swap device must be on the controller used for booting since 
!  * that is the only one attached here - the other controllers are attached 
!  * by /etc/autoconfig when it runs later.
   */
  
! xproot(csr)
! 	register struct	hpdevice *csr;
! 	{
  
+ 	if	(!csr)					/* XXX */
+ 		csr = (struct hpdevice *)0176700;	/* XXX */
+ 	xpattach(csr, 0);
+ 	}
+ 
  /*
   * Attach controller at xpaddr.  Mark as nonexistent if xpaddr is 0; otherwise
!  * attach slaves.  This routine must be called once per controller
!  * in ascending controller numbers.
!  *
!  * NOTE: This means that the 'xp' lines in /etc/dtab _MUST_ be in order
!  * starting with 'xp 0' first.
   */
+ 
  xpattach(xpaddr, unit)
  	register struct hpdevice *xpaddr;
! 	int unit;	/* controller number */
  {
  	register struct xp_controller *xc = &xp_controller[unit];
  	static int last_attached = -1;
  
  #ifdef UCB_METER
! 	if (xp_dkn < 0)
  		dk_alloc(&xp_dkn, NXPD+NXPC, "xp", 0L);
  #endif
  
  	if ((unsigned)unit >= NXPC)
  		return(0);
! 	if (xpaddr && (fioword(xpaddr) != -1)) {
  		xc->xp_addr = xpaddr;
  		if (fioword(&xpaddr->hpbae) != -1)
! 			xc->xp_rh70 = 1;
  	/*
  	 *  If already attached, ignore (don't want to renumber drives)
  	 */
***************
*** 367,373 ****
  			last_attached = unit;
  			xpslave(xpaddr, xc);
  		}
- #endif
  		return(1);
  	}
  	xc->xp_addr = 0;
--- 160,165 ----
***************
*** 374,383 ****
  	return(0);
  }
  
- #ifdef XP_PROBE
  /*
!  * Determine what drives are attached to a controller; guess their types and
!  * fill in the drive structures.
   */
  xpslave(xpaddr, xc)
  register struct hpdevice *xpaddr;
--- 166,174 ----
  	return(0);
  }
  
  /*
!  * Determine what drives are attached to a controller; the type and geometry
!  * information will be retrieved at open time from the disklabel.
   */
  xpslave(xpaddr, xc)
  register struct hpdevice *xpaddr;
***************
*** 389,395 ****
  	static int nxp = 0;
  
  	for (j = 0; j < 8; j++) {
! 		xpaddr->hpcs1.w = 0;
  		xpaddr->hpcs2.w = j;
  		xpaddr->hpcs1.w = HP_GO;	/* testing... */
  		delay(6000L);
--- 180,186 ----
  	static int nxp = 0;
  
  	for (j = 0; j < 8; j++) {
! 		xpaddr->hpcs1.w = HP_NOP;
  		xpaddr->hpcs2.w = j;
  		xpaddr->hpcs1.w = HP_GO;	/* testing... */
  		delay(6000L);
***************
*** 402,536 ****
  			xd = &xp_drive[nxp++];
  			xd->xp_ctlr = xc;
  			xd->xp_unit = j;
! 			/* If drive type is initialized, believe it. */
! 			if (xd->xp_type == 0) {
! 				xd->xp_type = xpaddr->hpdt & 077;
! 				xd->xp_type = xpmaptype(xd, xpaddr->hpsn);
! 			}
! 			for (st = xpst; st->type; st++)
! 				if (st->type == xd->xp_type) {
! 					xd->xp_nsect = st->nsect;
! 					xd->xp_ntrack = st->ntrack;
! 					xd->xp_nspc = st->nsect * st->ntrack;
! #ifdef BADSECT
! 					xd->xp_ncyl = st->ncyl;
! #endif
! 					xd->xp_sizes = st->sizes;
! 					xd->xp_ctlr->xp_flags |= st->flags;
! 					break;
! 				}
! 			if (!st->type) {
! 				printf("xp%d: drive type %o unrecognized\n",nxp - 1, xd->xp_type);
! 				xd->xp_ctlr = NULL;
! 			}
! 
! #ifdef UCB_METER
! 			if (xp_dkn >= 0 && xd->xp_ctlr)
! 				dk_wps[xd - &xp_drive[0]]
!  					= (long)xd->xp_nsect * (60L * 256L);
! #endif
  		}
  	}
  }
  
! static
! xpmaptype(xd, hpsn)
! 	register struct xp_drive *xd;
! 	register u_short hpsn;
! {
! 	register u_short type = xd->xp_type;
  
! 	/*
! 	 * Model-byte processing for SI controllers.
! 	 * NB:  Only deals with RM02, RM03 and RM05 emulations.
! 	 */
! 	if ((type == RM02 || type == RM03 || type == RM05)
! 	    && (hpsn & SIMB_LU) == xd->xp_unit) {
! 		switch (hpsn & (SIMB_MB & ~(SIMB_S6|SIMB_XX|SIRM03|SIRM05))) {
! 		case SI9775D:
! 			type = SI5;
! 			break;
  
! 		case SI9775M:
! 			type = RM05;
! 			break;
  
! 		case SI9730D:
! 			type = RM2X;
! 			break;
  
! 		case SI9766:
! 			type = RM05;
! 			break;
  
! 		case SI9762:
! 			type = RM03;
! 			break;
  
! 		case SICAPD:
! 			type = CAP;
! 			break;
  
! 		case SI9751D:
! 			type = SI;
! 			break;
! 		}
  	}
- 	return(type);
- }
- #endif XP_PROBE
  
! xpopen(dev)
! 	dev_t dev;
! {
  	register struct xp_drive *xd;
! 	register int unit = xpunit(dev);
  
! 	if (unit >= NXPD || !(xd = &xp_drive[unit])->xp_ctlr ||
! 		!xd->xp_ctlr->xp_addr)
! 		return (ENXIO);
! 	return (0);
! }
  
  xpstrategy(bp)
  register struct buf *bp;
! {
  	register struct xp_drive *xd;
! 	register int unit;
  	struct buf *dp;
! 	short pseudo_unit;
! 	int s;
! 	long bn;
  
! 	unit = dkunit(bp->b_dev);
! 	pseudo_unit = dkpart(bp->b_dev);
  
! 	if ((unit >= NXPD) || ((xd = &xp_drive[unit])->xp_ctlr == 0) ||
! 		(xd->xp_ctlr->xp_addr == 0)) {
  		bp->b_error = ENXIO;
! 		goto errexit;
! 	}
! 	if ((bp->b_blkno < 0) || ((bn = bp->b_blkno) + ((bp->b_bcount + 511)
! 		>> 9) > xd->xp_sizes[pseudo_unit].nblocks)) {
! 		bp->b_error = EINVAL;
! errexit:
! 		bp->b_flags |= B_ERROR;
! 		iodone(bp);
! 		return;
! 	}
! 	if ((xd->xp_ctlr->xp_flags & XP_RH70) == 0)
  		mapalloc(bp);
! 	bp->b_cylin = bn / xd->xp_nspc + xd->xp_sizes[pseudo_unit].cyloff;
  	dp = &xputab[unit];
  	s = splbio();
  	disksort(dp, bp);
! 	if (dp->b_active == 0) {
  		xpustart(unit);
! 		if (xd->xp_ctlr->xp_active == 0)
  			xpstart(xd->xp_ctlr);
! 	}
  	splx(s);
! }
  
  /*
   * Unit start routine.  Seek the drive to where the data are and then generate
--- 193,455 ----
  			xd = &xp_drive[nxp++];
  			xd->xp_ctlr = xc;
  			xd->xp_unit = j;
! /*
!  * Allocate the disklabel now.  This is very early in the system's life
!  * so fragmentation will be minimized if any labels are allocated from 
!  * main memory.  Then initialize the flags to indicate a drive is present.
! */
! 			xd->xp_label = disklabelalloc();
! 			xd->xp_flags = DKF_ALIVE;
  		}
  	}
  }
  
! xpopen(dev, flags, mode)
! 	dev_t	dev;
! 	int	flags, mode;
! 	{
! register struct xp_drive *xd;
! 	int	unit = XPUNIT(dev);
! 	int	i, part = dkpart(dev), rpm;
! register int	mask;
  
! 	if	(unit >= NXPD)
! 		return(ENXIO);
!  	xd = &xp_drive[unit];
! 	if	((xd->xp_flags & DKF_ALIVE) == 0)
! 		return(ENXIO);
! /*
!  * Now we read the label.  First wait for any pending opens/closes to
!  * complete.
! */
! 	while	(xd->xp_flags & (DKF_OPENING|DKF_CLOSING))
! 		sleep(xd, PRIBIO);
! /*
!  * On first open get label (which has the geometry information as well as
!  * the partition tables).  We may block reading the label so be careful to
!  * stop any other opens.
! */
! 	if	(xd->xp_open == 0)
! 		{
! 		xd->xp_flags |= DKF_OPENING;
! 		xpgetinfo(xd, dev);
! 		xd->xp_flags &= ~DKF_OPENING;
! 		wakeup(xd);
! 		}
! /*
!  * Need to make sure the partition is not out of bounds.  This requires
!  * mapping in the external label.  Since this only happens when a partition
!  * is opened (at mount time for example) it is unlikely to be  an efficiency
!  * concern.
! */
! 	mapseg5(xd->xp_label, LABELDESC);
! 	i = ((struct disklabel *)SEG5)->d_npartitions;
! 	rpm = ((struct disklabel *)SEG5)->d_rpm;
! 	normalseg5();
! 	if	(part >= i)
! 		return(ENXIO);
! #ifdef	UCB_METER
! 	if	(xp_dkn >= 0)
! 		dk_wps[xd - xp_drive] = (long) xd->xp_nsect * (rpm / 60) * 256L;
! #endif
! 	mask = 1 << part;
! 	dkoverlapchk(xd->xp_open, dev, xd->xp_label, "xp");
! 	if	(mode == S_IFCHR)
! 		xd->xp_copen |= mask;
! 	else if	(mode == S_IFBLK)
! 		xd->xp_bopen |= mask;
! 	else
! 		return(EINVAL);
! 	xd->xp_open |= mask;
! 	return(0);
! 	}
  
! xpclose(dev, flags, mode)
! 	dev_t	dev;
! 	int	flags, mode;
! 	{
! 	int	s;
! register int mask;
! register struct xp_drive *xd;
! 	int	unit = XPUNIT(dev);
  
! 	xd = &xp_drive[unit];
! 	mask = 1 << dkpart(dev);
! 	if	(mode == S_IFCHR)
! 		xd->xp_copen &= ~mask;
! 	else if	(mode == S_IFBLK)
! 		xd->xp_bopen &= ~mask;
! 	else
! 		return(EINVAL);
! 	xd->xp_open = xd->xp_copen | xd->xp_bopen;
! 	if	(xd->xp_open == 0)
! 		{
! 		xd->xp_flags |= DKF_CLOSING;
! 		s = splbio();
! 		while	(xputab[unit].b_actf)
! 			sleep(&xputab[unit], PRIBIO);
! 		xd->xp_flags &= ~DKF_CLOSING;
! 		splx(s);
! 		wakeup(xd);
! 		}
! 	return(0);
! 	}
  
! void
! xpdfltlbl(xd, lp)
! 	register struct	xp_drive *xd;
! 	register struct	disklabel *lp;
! 	{
! 	register struct partition *pi = &lp->d_partitions[0];
  
! /*
!  * NOTE: partition 0 ('a') is used to read the label.  Therefore 'a' must
!  * start at the beginning of the disk!  If there is no label or the label
!  * is corrupted then a label containing a geometry sufficient *only* to 
!  * read/write sector 1 (LABELSECTOR) is created.  1 track, 1 cylinder and
!  * 2 sectors per track.
! */
  
! 	bzero(lp, sizeof (*lp));
! 	lp->d_type = DTYPE_SMD;
! 	lp->d_secsize = 512;			/* XXX */
! 	lp->d_nsectors = LABELSECTOR + 1;	/* # sectors/track */
! 	lp->d_ntracks = 1;			/* # tracks/cylinder */
! 	lp->d_secpercyl = LABELSECTOR + 1;	/* # sectors/cylinder */
! 	lp->d_ncylinders = 1;			/* # cylinders */
! 	lp->d_npartitions = 1;			/* 1 partition  = 'a' */
! /*
!  * Need to put the information where the driver expects it.  This is normally
!  * done after reading the label.  Since we're creating a fake label we have to
!  * copy the invented geometry information to the right place.
! */
! 	xd->xp_nsect = lp->d_nsectors;
! 	xd->xp_ntrack = lp->d_ntracks;
! 	xd->xp_nspc = lp->d_secpercyl;
! 	xd->xp_ncyl = lp->d_ncylinders;
! 	xd->xp_dd0 = lp->d_drivedata[0];
  
! 	pi->p_size = LABELSECTOR + 1;
! 	pi->p_fstype = FS_V71K;
! 	pi->p_frag = 1;
! 	pi->p_fsize = 1024;
! 	bcopy(pi, xd->xp_parts, sizeof (lp->d_partitions));
  	}
  
! /*
!  * Read disklabel.  It is tempting to generalize this routine so that
!  * all disk drivers could share it.  However by the time all of the 
!  * necessary parameters are setup and passed the savings vanish.  Also,
!  * each driver has a different method of calculating the number of blocks
!  * to use if one large partition must cover the disk.
!  *
!  * This routine used to always return success and callers carefully checked
!  * the return status.  Silly.  This routine will fake a label (a single
!  * partition spanning the drive) if necessary but will never return an error.
!  *
!  * It is the caller's responsibility to check the validity of partition 
!  * numbers, etc.
! */
! 
! void
! xpgetinfo(xd, dev)
  	register struct xp_drive *xd;
! 	dev_t	dev;
! 	{
! 	struct	disklabel locallabel;
! 	char	*msg;
! 	register struct disklabel *lp = &locallabel;
  
! 	xpdfltlbl(xd, lp);
! 	msg = readdisklabel((dev & ~7) | 0, xpstrategy, lp);	/* 'a' */
! 	if	(msg != 0)
! 		{
! 		log(LOG_NOTICE, "xp%da using labelonly geometry: %s\n",
! 			XPUNIT(dev), msg);
! 		xpdfltlbl(xd, lp);
! 		}
! 	mapseg5(xd->xp_label, LABELDESC);
! 	bcopy(lp, (struct disklabel *)SEG5, sizeof (struct disklabel));
! 	normalseg5();
! 	bcopy(lp->d_partitions, xd->xp_parts, sizeof (lp->d_partitions));
! 	xd->xp_nsect = lp->d_nsectors;
! 	xd->xp_ntrack = lp->d_ntracks;
! 	xd->xp_nspc = lp->d_secpercyl;
! 	xd->xp_ncyl = lp->d_ncylinders;
! 	xd->xp_dd0 = lp->d_drivedata[0];
! 	return;
! 	}
  
  xpstrategy(bp)
  register struct buf *bp;
! 	{
  	register struct xp_drive *xd;
! 	register struct partition *pi;
! 	int	unit, part;
  	struct buf *dp;
! 	int	s;
! 	daddr_t	sz;
  
! 	unit = XPUNIT(bp->b_dev);
! 	part = dkpart(bp->b_dev);
! 	xd = &xp_drive[unit];
  
! 	if	(unit >= NXPD || !xd->xp_ctlr || !(xd->xp_flags & DKF_ALIVE))
! 		{
  		bp->b_error = ENXIO;
! 		goto bad;
! 		}
! 	pi = &xd->xp_parts[part];
! 
! 	sz = (bp->b_bcount + 511) >> 9;
! 	if	(bp->b_blkno < 0 || bp->b_blkno + sz > pi->p_size)
! 		{
! 		sz = pi->p_size - bp->b_blkno;
! 		/* If exactly at end of disk, return an EOF */
! 		if	(sz == 0)
! 			{
! 			bp->b_resid = bp->b_bcount;
! 			goto done;
! 			}
! 		/* or truncate if part of it fits */
! 		if	(sz < 0)
! 			{
! 			bp->b_error = EINVAL;
! 			goto bad;
! 			}
! 		bp->b_bcount = dbtob(sz);	/* compute byte count */
! 		}
! /*
!  * Check for write to write-protected label area.  This does not include
!  * sector 0 which is the boot block.
! */
! 	if	(bp->b_blkno + pi->p_offset <= LABELSECTOR &&
! 		 bp->b_blkno + pi->p_offset + sz > LABELSECTOR &&
! 		 !(bp->b_flags & B_READ) && !(xd->xp_flags & DKF_WLABEL))
! 		{
! 		bp->b_error = EROFS;
! 		goto bad;
! 		}
! 	if	(xd->xp_ctlr->xp_rh70 == 0)
  		mapalloc(bp);
! 	bp->b_cylin = (bp->b_blkno + pi->p_offset) / xd->xp_nspc;
  	dp = &xputab[unit];
  	s = splbio();
  	disksort(dp, bp);
! 	if	(dp->b_active == 0)
! 		{
  		xpustart(unit);
! 		if	(xd->xp_ctlr->xp_active == 0)
  			xpstart(xd->xp_ctlr);
! 		}
  	splx(s);
! 	return;
! bad:
! 	bp->b_flags |= B_ERROR;
! done:
! 	iodone(bp);
! 	return;
! 	}
  
  /*
   * Unit start routine.  Seek the drive to where the data are and then generate
***************
*** 540,551 ****
   * for transfer (to avoid positioning forever without transferring).
   */
  xpustart(unit)
! int unit;
  {
  	register struct xp_drive *xd;
  	register struct hpdevice *xpaddr;
  	register struct buf *dp;
! 	struct buf *bp;
  	daddr_t bn;
  	int	sn, cn, csn;
  
--- 459,470 ----
   * for transfer (to avoid positioning forever without transferring).
   */
  xpustart(unit)
! 	int unit;
  {
  	register struct xp_drive *xd;
  	register struct hpdevice *xpaddr;
  	register struct buf *dp;
! 	struct buf *bp, *bbp;
  	daddr_t bn;
  	int	sn, cn, csn;
  
***************
*** 554,561 ****
  	xpaddr->hpcs2.w = xd->xp_unit;
  	xpaddr->hpcs1.c[0] = HP_IE;
  	xpaddr->hpas = 1 << xd->xp_unit;
- 	if (unit >= NXPD)
- 		return;
  #ifdef UCB_METER
  	if (xp_dkn >= 0)
  		dk_busy &= ~(1 << (xp_dkn + unit));
--- 473,478 ----
***************
*** 573,595 ****
  	/*
  	 * If drive has just come up, set up the pack.
  	 */
! #ifdef BADSECT
! 	if (((xpaddr->hpds & HPDS_VV) == 0) || (xp_init[unit] == 0)) {
! 		struct buf *bbp = &bxpbuf[unit];
! #else
! 	if ((xpaddr->hpds & HPDS_VV) == 0) {
! #endif
! 	/* SHOULD WARN SYSTEM THAT THIS HAPPENED */
! #ifdef XP_DEBUG
! 		printf("preset-unit=%d\n", unit);
! #endif
  		xpaddr->hpcs1.c[0] = HP_IE | HP_PRESET | HP_GO;
- #ifdef XP_DEBUG
- 		printf("preset done\n");
- #endif
  		xpaddr->hpof = HPOF_FMT22;
  #ifdef BADSECT
! 		xp_init[unit] = 1;
  		bbp->b_flags = B_READ | B_BUSY | B_PHYS;
  		bbp->b_dev = bp->b_dev | 7;	/* "h" partition whole disk */
  		bbp->b_bcount = sizeof(struct dkbad);
--- 490,511 ----
  	/*
  	 * If drive has just come up, set up the pack.
  	 */
! 	if (((xpaddr->hpds & HPDS_VV) == 0) || !(xd->xp_flags & DKF_ONLINE)) {
  		xpaddr->hpcs1.c[0] = HP_IE | HP_PRESET | HP_GO;
  		xpaddr->hpof = HPOF_FMT22;
+ 		xd->xp_flags |= DKF_ONLINE;
+ #ifdef	XPDEBUG
+ 		log(LOG_NOTICE, "xp%d preset done\n", unit);
+ #endif
+ 	}
+ /*
+  * XXX - The 'h' partition is used below to access the bad block area.  This
+  * XXX - will almost certainly be wrong if the user has defined another 
+  * XXX - partition to span the entire drive including the bad block area.  It
+  * XXX - is not known what to do about this.
+ */
  #ifdef BADSECT
! 		bbp = &bxpbuf[unit];
  		bbp->b_flags = B_READ | B_BUSY | B_PHYS;
  		bbp->b_dev = bp->b_dev | 7;	/* "h" partition whole disk */
  		bbp->b_bcount = sizeof(struct dkbad);
***************
*** 596,614 ****
  		bbp->b_un.b_addr = (caddr_t)&xpbad[unit];
  		bbp->b_blkno = (daddr_t)xd->xp_ncyl * xd->xp_nspc - xd->xp_nsect;
  		bbp->b_cylin = xd->xp_ncyl - 1;
! 		if ((xd->xp_ctlr->xp_flags & XP_RH70) == 0)
  			mapalloc(bbp);
  		dp->b_actf = bbp;
  		bbp->av_forw = bp;
  		bp = bbp;
  #endif BADSECT
! 	}
  #if NXPD > 1
  	/*
  	 * If drive is offline, forget about positioning.
  	 */
! 	if ((xpaddr->hpds & (HPDS_DPR | HPDS_MOL)) != (HPDS_DPR | HPDS_MOL))
  		goto done;
  	/*
  	 * Figure out where this transfer is going to
  	 * and see if we are close enough to justify not searching.
--- 512,533 ----
  		bbp->b_un.b_addr = (caddr_t)&xpbad[unit];
  		bbp->b_blkno = (daddr_t)xd->xp_ncyl * xd->xp_nspc - xd->xp_nsect;
  		bbp->b_cylin = xd->xp_ncyl - 1;
! 		if (xd->xp_ctlr->xp_rh70 == 0)
  			mapalloc(bbp);
  		dp->b_actf = bbp;
  		bbp->av_forw = bp;
  		bp = bbp;
  #endif BADSECT
! 
  #if NXPD > 1
  	/*
  	 * If drive is offline, forget about positioning.
  	 */
! 	if	(xpaddr->hpds & (HPDS_DREADY) != (HPDS_DREADY))
! 		{
! 		xd->xp_flags &= ~DKF_ONLINE;
  		goto done;
+ 		}
  	/*
  	 * Figure out where this transfer is going to
  	 * and see if we are close enough to justify not searching.
***************
*** 619,628 ****
  	sn += xd->xp_nsect - XP_SDIST;
  	sn %= xd->xp_nsect;
  
! 	if (((xd->xp_ctlr->xp_flags & XP_NOCC) && (xd->xp_cc != cn))
! 		|| xpaddr->hpcc != cn)
  		goto search;
! 	if (xd->xp_ctlr->xp_flags & XP_NOSEARCH)
  		goto done;
  	csn = (xpaddr->hpla >> 6) - sn + XP_SDIST - 1;
  	if (csn < 0)
--- 538,547 ----
  	sn += xd->xp_nsect - XP_SDIST;
  	sn %= xd->xp_nsect;
  
! 	if	((!(xd->xp_dd0 & XP_CC) && (xd->xp_cc != cn))
! 		 || xpaddr->hpcc != cn)
  		goto search;
! 	if	(xd->xp_dd0 & XP_NOSEARCH)
  		goto done;
  	csn = (xpaddr->hpla >> 6) - sn + XP_SDIST - 1;
  	if (csn < 0)
***************
*** 632,638 ****
  search:
  	xpaddr->hpdc = cn;
  	xpaddr->hpda = sn;
! 	xpaddr->hpcs1.c[0] = (xd->xp_ctlr->xp_flags & XP_NOSEARCH) ?
  		(HP_IE | HP_SEEK | HP_GO) : (HP_IE | HP_SEARCH | HP_GO);
  	xd->xp_cc = cn;
  #ifdef UCB_METER
--- 551,557 ----
  search:
  	xpaddr->hpdc = cn;
  	xpaddr->hpda = sn;
! 	xpaddr->hpcs1.c[0] = (xd->xp_dd0 & XP_NOSEARCH) ?
  		(HP_IE | HP_SEEK | HP_GO) : (HP_IE | HP_SEARCH | HP_GO);
  	xd->xp_cc = cn;
  #ifdef UCB_METER
***************
*** 671,679 ****
  	register struct buf *bp;
  	struct xp_drive *xd;
  	struct buf *dp;
- 	short pseudo_unit;
  	daddr_t bn;
! 	int	unit, sn, tn, cn;
  
  	xpaddr = xc->xp_addr;
  loop:
--- 590,597 ----
  	register struct buf *bp;
  	struct xp_drive *xd;
  	struct buf *dp;
  	daddr_t bn;
! 	int	unit, part, sn, tn, cn;
  
  	xpaddr = xc->xp_addr;
  loop:
***************
*** 683,689 ****
--- 601,618 ----
  	if ((dp = xc->xp_actf) == NULL)
  		return;
  	if ((bp = dp->b_actf) == NULL) {
+ /*
+  * No more requests for this drive, remove from controller queue and
+  * look at next drive.  We know we're at the head of the controller queue.
+  * The drive may not need anything, in which case it might be shutting
+  * down in xpclose() and a wakeup is done.
+ */
+ 		dp->b_active = 0;
  		xc->xp_actf = dp->b_forw;
+ 		unit = dp - xputab;
+ 		xd = &xp_drive[unit];
+ 		if	(xd->xp_open == 0)
+ 			wakeup(dp);	/* finish close protocol */
  		goto loop;
  	}
  	/*
***************
*** 690,701 ****
  	 * Mark controller busy and determine destination of this request.
  	 */
  	xc->xp_active++;
! 	pseudo_unit = dkpart(bp->b_dev);
! 	unit = dkunit(bp->b_dev);
  	xd = &xp_drive[unit];
  	bn = bp->b_blkno;
! 	cn = xd->xp_sizes[pseudo_unit].cyloff;
! 	cn += bn / xd->xp_nspc;
  	sn = bn % xd->xp_nspc;
  	tn = sn / xd->xp_nsect;
  	sn = sn % xd->xp_nsect;
--- 619,629 ----
  	 * Mark controller busy and determine destination of this request.
  	 */
  	xc->xp_active++;
! 	part = dkpart(bp->b_dev);
! 	unit = XPUNIT(bp->b_dev);
  	xd = &xp_drive[unit];
  	bn = bp->b_blkno;
! 	cn = (xd->xp_parts[part].p_offset + bn) / xd->xp_nspc;
  	sn = bn % xd->xp_nspc;
  	tn = sn / xd->xp_nsect;
  	sn = sn % xd->xp_nsect;
***************
*** 706,712 ****
  	/*
   	 * Check that it is ready and online.
  	 */
! 	if ((xpaddr->hpds & (HPDS_DPR | HPDS_MOL)) != (HPDS_DPR | HPDS_MOL)) {
  		xc->xp_active = 0;
  		dp->b_errcnt = 0;
  		dp->b_actf = bp->av_forw;
--- 634,641 ----
  	/*
   	 * Check that it is ready and online.
  	 */
! 	if ((xpaddr->hpds & HPDS_DREADY) != (HPDS_DREADY)) {
! 		xd->xp_flags &= ~DKF_ONLINE;
  		xc->xp_active = 0;
  		dp->b_errcnt = 0;
  		dp->b_actf = bp->av_forw;
***************
*** 714,719 ****
--- 643,650 ----
  		iodone(bp);
  		goto loop;
  	}
+ 	xd->xp_flags |= DKF_ONLINE;
+ 
  	if (dp->b_errcnt >= 16 && (bp->b_flags & B_READ)) {
  		xpaddr->hpof = xp_offset[dp->b_errcnt & 017] | HPOF_FMT22;
  		xpaddr->hpcs1.w = HP_OFFSET | HP_GO;
***************
*** 722,728 ****
  	xpaddr->hpdc = cn;
  	xpaddr->hpda = (tn << 8) + sn;
  	xpaddr->hpba = bp->b_un.b_addr;
! 	if (xc->xp_flags & XP_RH70)
  		xpaddr->hpbae = bp->b_xmem;
  	xpaddr->hpwc = -(bp->b_bcount >> 1);
  	/*
--- 653,659 ----
  	xpaddr->hpdc = cn;
  	xpaddr->hpda = (tn << 8) + sn;
  	xpaddr->hpba = bp->b_un.b_addr;
! 	if (xc->xp_rh70)
  		xpaddr->hpbae = bp->b_xmem;
  	xpaddr->hpwc = -(bp->b_bcount >> 1);
  	/*
***************
*** 784,790 ****
  			if (xpecc(bp, CONT))
  				return;
  #endif
! 		unit = dkunit(bp->b_dev);
  		xd = &xp_drive[unit];
  		xpaddr->hpcs2.c[0] = xd->xp_unit;
  		/*
--- 715,721 ----
  			if (xpecc(bp, CONT))
  				return;
  #endif
! 		unit = XPUNIT(bp->b_dev);
  		xd = &xp_drive[unit];
  		xpaddr->hpcs2.c[0] = xd->xp_unit;
  		/*
***************
*** 796,802 ****
  			/*
  			 * Give up on write locked deviced immediately.
  			 */
! 				printf("xp%d: write locked\n", unit);
  				bp->b_flags |= B_ERROR;
  #ifdef BADSECT
  			}
--- 727,733 ----
  			/*
  			 * Give up on write locked deviced immediately.
  			 */
! 				log(LOG_NOTICE, "xp%d: write locked\n", unit);
  				bp->b_flags |= B_ERROR;
  #ifdef BADSECT
  			}
***************
*** 823,836 ****
  				if (++dp->b_errcnt > 28) {
  hard:
  					harderr(bp, "xp");
! #ifdef XP_DEBUG
! 					/*
! 					 * for RM drives
! 					 */
! 					printf("cs2=%b er1=%b er2=%b\n",xpaddr->hpcs2.w, HPCS2_BITS, xpaddr->hper1, HPER1_BITS, xpaddr->rmer2, RMER2_BITS);
! #else
! 					printf("cs2=%b er1=%b\n", xpaddr->hpcs2.w, HPCS2_BITS, xpaddr->hper1, HPER1_BITS);
! #endif
  					bp->b_flags |= B_ERROR;
  				}
  				else
--- 754,763 ----
  				if (++dp->b_errcnt > 28) {
  hard:
  					harderr(bp, "xp");
! 					log(LOG_NOTICE,"cs2=%b er1=%b er2=%b\n",
! 						xpaddr->hpcs2.w, HPCS2_BITS,
! 						xpaddr->hper1, HPER1_BITS,
! 						xpaddr->rmer2, RMER2_BITS);
  					bp->b_flags |= B_ERROR;
  				}
  				else
***************
*** 892,897 ****
--- 819,825 ----
   */
  xpecc(bp, flag)
  register struct	buf *bp;
+ 	int	flag;
  {
  	register struct xp_drive *xd;
  	register struct hpdevice *xpaddr;
***************
*** 910,916 ****
  	 * ndone is #bytes including the error which is assumed to be in the
  	 * last disk page transferred.
  	 */
! 	unit = dkunit(bp->b_dev);
  	xd = &xp_drive[unit];
  	xpaddr = xd->xp_ctlr->xp_addr;
  #ifdef BADSECT
--- 838,844 ----
  	 * ndone is #bytes including the error which is assumed to be in the
  	 * last disk page transferred.
  	 */
! 	unit = XPUNIT(bp->b_dev);
  	xd = &xp_drive[unit];
  	xpaddr = xd->xp_ctlr->xp_addr;
  #ifdef BADSECT
***************
*** 940,946 ****
  	sn %= xd->xp_nsect;
  	switch (flag) {
  		case ECC:
! 			printf("xp%d%c: soft ecc sn%D\n",unit, 'a' + (minor(bp->b_dev) & 07), bp->b_blkno + (npx - 1));
  			wrong = xpaddr->hpec2;
  			if (wrong == 0) {
  				xpaddr->hpof = HPOF_FMT22;
--- 868,876 ----
  	sn %= xd->xp_nsect;
  	switch (flag) {
  		case ECC:
! 			log(LOG_NOTICE, "xp%d%c: soft ecc sn%D\n",
! 				unit, 'a' + dkpart(bp->b_dev),
! 				bp->b_blkno + (npx - 1));
  			wrong = xpaddr->hpec2;
  			if (wrong == 0) {
  				xpaddr->hpof = HPOF_FMT22;
***************
*** 988,1003 ****
  			tn = sn;
  			tn /= xd->xp_nsect;
  			sn %= xd->xp_nsect;
! #ifdef DEBUG
! 			printf("revector to cn %d tn %d sn %d\n", cn, tn, sn);
! #endif
  			wc = -(512 / (int)NBPW);
  			break;
  		case CONT:
  			bp->b_flags &= ~B_BAD;
! #ifdef DEBUG
! 			printf("xpecc CONT: bn %D cn %d tn %d sn %d\n", bn, cn, tn, sn);
! #endif
  			break;
  #endif BADSECT
  	}
--- 918,931 ----
  			tn = sn;
  			tn /= xd->xp_nsect;
  			sn %= xd->xp_nsect;
! 			log(LOG_NOTICE, "revector to cn %d tn %d sn %d\n",
! 				cn, tn, sn);
  			wc = -(512 / (int)NBPW);
  			break;
  		case CONT:
  			bp->b_flags &= ~B_BAD;
! 			log(LOG_NOTICE, "xpecc CONT: bn %D cn %d tn %d sn %d\n",
! 				bn, cn, tn, sn);
  			break;
  #endif BADSECT
  	}
***************
*** 1017,1028 ****
  	xpaddr->hpda = (tn << 8) + sn;
  	xpaddr->hpwc = wc;
  	xpaddr->hpba = (caddr_t)addr;
! 	if (xd->xp_ctlr->xp_flags & XP_RH70)
  		xpaddr->hpbae = (int)(addr >> 16);
  	xpaddr->hpcs1.w = ocmd;
  	return (1);
  }
  
  #ifdef XP_DUMP
  /*
   * Dump routine.  Dumps from dumplo to end of memory/end of disk section for
--- 945,969 ----
  	xpaddr->hpda = (tn << 8) + sn;
  	xpaddr->hpwc = wc;
  	xpaddr->hpba = (caddr_t)addr;
! 	if (xd->xp_ctlr->xp_rh70)
  		xpaddr->hpbae = (int)(addr >> 16);
  	xpaddr->hpcs1.w = ocmd;
  	return (1);
  }
  
+ xpioctl(dev, cmd, data, flag)
+ 	dev_t	dev;
+ 	int	cmd;
+ 	caddr_t	data;
+ 	int	flag;
+ 	{
+ 	register int error;
+ 	struct	dkdevice *disk = &xp_drive[XPUNIT(dev)].xp_dk;
+ 
+ 	error = ioctldisklabel(dev, cmd, data, flag, disk, xpstrategy);
+ 	return(error);
+ 	}
+ 
  #ifdef XP_DUMP
  /*
   * Dump routine.  Dumps from dumplo to end of memory/end of disk section for
***************
*** 1032,1120 ****
  
  xpdump(dev)
  	dev_t dev;
! {
! 	/*
! 	 * ONLY USE 2 REGISTER VARIABLES, OR C COMPILER CHOKES
! 	 */
! 	register struct xp_drive *xd;
  	register struct hpdevice *xpaddr;
  	daddr_t bn, dumpsize;
! 	long paddr;
! 	int	sn, count;
! 	struct ubmap *ubp;
  
! 	if ((bdevsw[major(dev)].d_strategy != xpstrategy)	/* paranoia */
! 		|| ((dev=minor(dev)) > (NXPD << 3)))
  		return(EINVAL);
! 	xd = &xp_drive[xpunit(dev)];
! 	dev &= 07;
! 	if (xd->xp_ctlr == 0)
! 		return(EINVAL);
  	xpaddr = xd->xp_ctlr->xp_addr;
! 	dumpsize = xd->xp_sizes[dev].nblocks;
! 	if ((dumplo < 0) || (dumplo >= dumpsize))
  		return(EINVAL);
! 	dumpsize -= dumplo;
  	xpaddr->hpcs2.w = xd->xp_unit;
! 	if ((xpaddr->hpds & HPDS_VV) == 0) {
  		xpaddr->hpcs1.w = HP_DCLR | HP_GO;
  		xpaddr->hpcs1.w = HP_PRESET | HP_GO;
  		xpaddr->hpof = HPOF_FMT22;
! 	}
! 	if ((xpaddr->hpds & (HPDS_DPR | HPDS_MOL)) != (HPDS_DPR | HPDS_MOL))
  		return(EFAULT);
  	ubp = &UBMAP[0];
! 	for (paddr = 0L; dumpsize > 0; dumpsize -= count) {
! 		count = dumpsize>DBSIZE? DBSIZE: dumpsize;
! 		bn = dumplo + (paddr >> PGSHIFT);
! 		xpaddr->hpdc = bn / xd->xp_nspc + xd->xp_sizes[dev].cyloff;
  		sn = bn % xd->xp_nspc;
  		xpaddr->hpda = ((sn / xd->xp_nsect) << 8) | (sn % xd->xp_nsect);
  		xpaddr->hpwc = -(count << (PGSHIFT - 1));
  		xpaddr->hper1 = 0;
  		xpaddr->hper3 = 0;
! 		if (ubmap && ((xd->xp_ctlr->xp_flags & XP_RH70) == 0)) {
  			ubp->ub_lo = loint(paddr);
  			ubp->ub_hi = hiint(paddr);
  			xpaddr->hpba = 0;
  			xpaddr->hpcs1.w = HP_WCOM | HP_GO;
! 		}
! 		else {
  			/*
  			 * Non-UNIBUS map, or 11/70 RH70 (MASSBUS)
  			 */
! 			xpaddr->hpba = loint(paddr);
! 			if (xd->xp_ctlr->xp_flags & XP_RH70)
  				xpaddr->hpbae = hiint(paddr);
  			xpaddr->hpcs1.w = HP_WCOM | HP_GO | ((paddr >> 8) & (03 << 8));
! 		}
  		/* Emulex controller emulating two RM03's needs a delay */
  		delay(50000L);
! 		while (xpaddr->hpcs1.w & HP_GO)
  			continue;
! 		if (xpaddr->hpcs1.w & HP_TRE) {
! 			if (xpaddr->hpcs2.w & HPCS2_NEM)
! 				return(0);	/* made it to end of memory */
  			return(EIO);
- 		}
  		paddr += (DBSIZE << PGSHIFT);
! 	}
! 	return(0);		/* filled disk minor dev */
  }
  #endif XP_DUMP
  
  /*
!  * By this time either the slaves have been "probed" for or the drive
!  * information was statically initialized - either way the lookup of
!  * partition size is straightforward.
  */
  daddr_t
  xpsize(dev)
! 	register dev_t	dev;
  	{
  	register struct xp_drive *xd;
  
! 	xd = &xp_drive[xpunit(dev)];
! 	return(xd->xp_sizes[dev & 7].nblocks);
  	}
! #endif NXPD
--- 973,1087 ----
  
  xpdump(dev)
  	dev_t dev;
! 	{
! 	struct xp_drive *xd;
  	register struct hpdevice *xpaddr;
+ 	struct	partition *pi;
  	daddr_t bn, dumpsize;
! 	long	paddr;
! 	int	sn, count, memblks, unit;
! 	register struct	ubmap *ubp;
  
! 	unit = XPUNIT(dev);
! 	xd = &xp_drive[unit];
! 
! 	if	(unit > NXPD || xd->xp_ctlr == 0)
  		return(EINVAL);
! 	if	(!(xd->xp_flags & DKF_ALIVE))
! 		return(ENXIO);
! 	if	(pi->p_fstype != FS_SWAP)
! 		return(EFTYPE);
! 
! 	pi = &xd->xp_parts[dkpart(dev)];
  	xpaddr = xd->xp_ctlr->xp_addr;
! 
! 	dumpsize = xpsize(dev) - dumplo;
! 	memblks = ctod(physmem);
! 
! 	if	(dumplo < 0 || dumpsize <= 0)
  		return(EINVAL);
! 	if	(memblks > dumpsize)
! 		memblks = dumpsize;
! 	bn = dumplo + pi->p_offset;
! 
  	xpaddr->hpcs2.w = xd->xp_unit;
! 	if	((xpaddr->hpds & HPDS_VV) == 0)
! 		{
  		xpaddr->hpcs1.w = HP_DCLR | HP_GO;
  		xpaddr->hpcs1.w = HP_PRESET | HP_GO;
  		xpaddr->hpof = HPOF_FMT22;
! 		}
! 	if	((xpaddr->hpds & HPDS_DREADY) != (HPDS_DREADY))
  		return(EFAULT);
  	ubp = &UBMAP[0];
! 	for	(paddr = 0L; memblks > 0; )
! 		{
! 		count = MIN(memblks, DBSIZE);
! 		xpaddr->hpdc = bn / xd->xp_nspc;
  		sn = bn % xd->xp_nspc;
  		xpaddr->hpda = ((sn / xd->xp_nsect) << 8) | (sn % xd->xp_nsect);
  		xpaddr->hpwc = -(count << (PGSHIFT - 1));
  		xpaddr->hper1 = 0;
  		xpaddr->hper3 = 0;
! 		if	(ubmap && (xd->xp_ctlr->xp_rh70 == 0))
! 			{
  			ubp->ub_lo = loint(paddr);
  			ubp->ub_hi = hiint(paddr);
  			xpaddr->hpba = 0;
  			xpaddr->hpcs1.w = HP_WCOM | HP_GO;
! 			}
! 		else
! 			{
  			/*
  			 * Non-UNIBUS map, or 11/70 RH70 (MASSBUS)
  			 */
! 			xpaddr->hpba = (caddr_t)loint(paddr);
! 			if	(xd->xp_ctlr->xp_rh70)
  				xpaddr->hpbae = hiint(paddr);
  			xpaddr->hpcs1.w = HP_WCOM | HP_GO | ((paddr >> 8) & (03 << 8));
! 			}
  		/* Emulex controller emulating two RM03's needs a delay */
  		delay(50000L);
! 		while	(xpaddr->hpcs1.w & HP_GO)
  			continue;
! 		if	(xpaddr->hpcs1.w & HP_TRE)
  			return(EIO);
  		paddr += (DBSIZE << PGSHIFT);
! 		bn += count;
! 		memblks -= count;
! 		}
! 	return(0);
  }
  #endif XP_DUMP
  
  /*
!  * Return the number of blocks in a partition.  Call xpopen() to read the
!  * label if necessary.  If an open is necessary then a matching close
!  * will be done.
  */
  daddr_t
  xpsize(dev)
! 	register dev_t dev;
  	{
  	register struct xp_drive *xd;
+ 	daddr_t	psize;
+ 	int	didopen = 0;
  
! 	xd = &xp_drive[XPUNIT(dev)];
! /*
!  * This should never happen but if we get called early in the kernel's
!  * life (before opening the swap or root devices) then we have to do
!  * the open here.
! */
! 	if	(xd->xp_open == 0)
! 		{
! 		if	(xpopen(dev, FREAD|FWRITE, S_IFBLK))
! 			return(-1);
! 		didopen = 1;
! 		}
! 	psize = xd->xp_parts[dkpart(dev)].p_size;
! 	if	(didopen)
! 		xpclose(dev, FREAD|FWRITE, S_IFBLK);
! 	return(psize);
  	}
! #endif /* NXPD */
*** /usr/src/sys/conf/config.old	Tue Feb 28 20:10:03 1995
--- /usr/src/sys/conf/config	Fri Jul 21 20:55:37 1995
***************
*** 1,6 ****
--- 1,9 ----
  #! /bin/sh
  #	2.11BSD script to set up a new kernel configuration directory.
  #
+ #	1995/07/21 - remove XP_PROBE, the kernel no longer probes for disk
+ #		     type because that information is obtained from the 
+ #		     disklabel.
  #	2/28/95	- fixed errors introduced earlier.  remove the chmod at the
  #		  end, rely instead on the system administrator's choice of
  #		  umask.
***************
*** 237,245 ****
  echo "#define NXPC	$NXPC"		>> ../$MACHINE/xp.h
  if [ $DUMPROUTINE = xpdump ]; then
  	echo "#define XP_DUMP 1"	>> ../$MACHINE/xp.h
- fi
- if [ $XP_PROBE = YES ]; then
- 	echo "#define XP_PROBE 1"	>> ../$MACHINE/xp.h
  fi
  
  echo "Creating Makefile for $MACHINE".
--- 240,245 ----
*** /usr/src/sys/conf/GENERIC.old	Tue Feb 14 20:41:01 1995
--- /usr/src/sys/conf/GENERIC	Fri Jul 21 20:52:39 1995
***************
*** 1,3 ****
--- 1,5 ----
+ # 1995/07/21 - XP_PROBE removed.
+ #
  # Machine configuration file for 2.11BSD distributed kernel.
  #
  # Format:
***************
*** 145,158 ****
  
  NSI		0		# SI 9500 driver for CDC 9766 disks
  
- # Because the disk drive type registers conflict with other DEC
- # controllers, you cannot use XP_PROBE for the Ampex 9300 and
- # Diva drives.  Read through /sys/pdpuba/hpreg.h and /sys/pdpuba/xp.c
- # for information on how to initialize for these drives.
  NXPC		1		# NXPD controllers (RH70/RH11 style)
  NXPD		2		# RM02/03/05, RP04/05/06, CDC 9766,
  				# Ampex 9300, Diva, Fuji 160, SI Eagle.
- XP_PROBE	YES		# check drive types at boot
  
  NRAM		0		# RAM disk size (512-byte blocks)
  
--- 147,155 ----
*** /usr/src/sys/pdp/conf.c.old	Mon Jun 19 20:36:34 1995
--- /usr/src/sys/pdp/conf.c	Mon Jul 24 21:46:47 1995
***************
*** 3,9 ****
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)conf.c	2.7 (2.11BSD GTE) 1995/06/19
   */
  
  #include "param.h"
--- 3,9 ----
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)conf.c	2.8 (2.11BSD GTE) 1995/07/24
   */
  
  #include "param.h"
***************
*** 58,69 ****
  
  #include "xp.h"
  #if NXPD > 0
! int	xpopen(), xpstrategy(), xproot();
  daddr_t	xpsize();
- #define	xpclose		nulldev
  #else
  #define	xpopen		nodev
  #define	xpclose		nodev
  #define	xproot		nulldev
  #define	xpstrategy	nodev
  #define	xpsize		NULL
--- 58,69 ----
  
  #include "xp.h"
  #if NXPD > 0
! int	xpopen(), xpstrategy(), xproot(), xpclose(), xpioctl();
  daddr_t	xpsize();
  #else
  #define	xpopen		nodev
  #define	xpclose		nodev
+ #define	xpioctl		nodev
  #define	xproot		nulldev
  #define	xpstrategy	nodev
  #define	xpsize		NULL
***************
*** 431,437 ****
  	sistrategy,
  /* xp = 19 */
  	xpopen,		xpclose,	rawrw,		rawrw,
! 	nodev,		nulldev,	0,		seltrue,
  	xpstrategy,
  /* br = 20 */
  	bropen,		brclose,	rawrw,		rawrw,
--- 431,437 ----
  	sistrategy,
  /* xp = 19 */
  	xpopen,		xpclose,	rawrw,		rawrw,
! 	xpioctl,	nulldev,	0,		seltrue,
  	xpstrategy,
  /* br = 20 */
  	bropen,		brclose,	rawrw,		rawrw,
*** /usr/src/sys/pdpstand/xp.c.old	Thu Jun  8 19:38:21 1995
--- /usr/src/sys/pdpstand/xp.c	Tue Aug  1 22:51:44 1995
***************
*** 3,9 ****
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)xp.c	2.1 (2.11BSD) 1995/06/08
   */
  
  /*
--- 3,9 ----
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)xp.c	2.2 (2.11BSD) 1995/08/01
   */
  
  /*
***************
*** 23,117 ****
  		(struct hpdevice *)-1
  		};
  
  /*
!  * Drive type; declared so we can patch; see hpreg.h for more information.
!  */
! int	xptype[NXP] = 0;
  
  xpstrategy(io, func)
  	register struct iob *io;
  {
- 	int unit = io->i_unit;
- 	int ctlr = io->i_ctlr;
  	int i;
- 	register nm_sect_per_cyl, nsect;
  	daddr_t bn;
  	int sn, cn, tn, bae, lo16;
! 	struct hpdevice *xpaddr = XPcsr[ctlr];
  
  	bn = io->i_bn;
! 	/*
! 	 * The weirdness involving bit 2 (04) in the unit # was removed
! 	 * because 1) the xp driver in the kernel didn't know about it,
! 	 * 2) no mention was made in any .h file or documentation/notes
! 	*/
! 	xpaddr->hpcs2.w = unit;
  
  	if ((xpaddr->hpds & HPDS_VV) == 0) {
  		xpaddr->hpcs1.c[0] = HP_PRESET|HP_GO;
  		xpaddr->hpof = HPOF_FMT22;
  	}
! 	/*
!  	 *	The weirdness of (possibly) looking at the console switch
!  	 *	register to tell what type of disk we have here was removed
! 	 *	because 1) most systems do not have one, 2) space contraints
! 	 *	imposed by adding multi controller support were creating a
! 	 * 	size problem, and 3) an alternative method is provided for
! 	 *	setting the type (the address and content is printed).
!  	 */
! 	
! 	if (xptype[ctlr] == 0) {
! 		xptype[ctlr] = (xpaddr->hpdt & 077);
! 		printf("\n&xptype=0%o xptype[%d]=0%o\n", xptype, ctlr, 
! 			xptype[ctlr]);
! 	}
  
- 	switch (xptype[ctlr]) {
- 	case RP04:
- 	case RP05:
- 	case RP06:
- 		nm_sect_per_cyl = HP_SECT * HP_TRAC;
- 		nsect = HP_SECT;
- 		break;
- 	case RM02:
- 	case RM03:
- 		nm_sect_per_cyl = RM_SECT * RM_TRAC;
- 		nsect = RM_SECT;
- 		break;
- 	case RM05:
- 	case RM5X:
- 		nm_sect_per_cyl = RM5_SECT * RM5_TRAC;
- 		nsect = RM5_SECT;
- 		break;
- 	case CAP:
- 		nm_sect_per_cyl = CAP_SECT * CAP_TRAC;
- 		nsect = CAP_SECT;
- 		break;
- 	case SI5:
- 		nm_sect_per_cyl = SI5_SECT * SI5_TRAC;
- 		nsect = SI5_SECT;
- 		break;
- 	case SI:
- 		nm_sect_per_cyl = SI_SECT * SI_TRAC;
- 		nsect = SI_SECT;
- 		break;
- 	case RM2X:
- 		nm_sect_per_cyl = RM2X_SECT * RM2X_TRAC;
- 		nsect = RM2X_SECT;
- 		break;
- 	case DV:
- 		nm_sect_per_cyl = DV_SECT * DV_TRAC;
- 		nsect = DV_SECT;
- 		break;
- 	default:
- 		printf("xp%d: unknown type 0%o\n", ctlr, xptype[ctlr]);
- 		return(-1);	
- 	}
- 	cn = bn/(nm_sect_per_cyl);
- 	sn = bn%(nm_sect_per_cyl);
- 	tn = sn/nsect;
- 	sn = sn%nsect;
- 
  	iomapadr(io->i_ma, &bae, &lo16);
  	xpaddr->hpdc = cn;
  	xpaddr->hpda = (tn << 8) + sn;
--- 23,93 ----
  		(struct hpdevice *)-1
  		};
  
+ 	static	char	xpinit[NXP][8];		/* XXX */
+ 
+ xpopen(io)
+ 	register struct iob *io;
+ 	{
+ 	register struct disklabel *lp = &io->i_label;
+ 	register struct	hpdevice *xpaddr;
+ 	int	dummy;
+ 
+ 	if	(genopen(NXP, io) < 0)
+ 		return(-1);
  /*
!  * If this is the first access for the drive check to see if it is
!  * present.  If the drive is present then read the label.
! */
! 	if	(xpinit[io->i_ctlr][io->i_unit] == 0)
! 		{
! 		xpaddr = XPcsr[io->i_ctlr];
! 		xpaddr->hpcs1.w = HP_NOP;
! 		xpaddr->hpcs2.w = io->i_unit;
! 		xpaddr->hpcs1.w = HP_GO;
! 		delay(6000);
! 		dummy = xpaddr->hpds;
! 		if	(xpaddr->hpcs2.w & HPCS2_NED)
! 			{
! 			xpaddr->hpcs2.w = HPCS2_CLR;
! 			return(-1);
! 			}
! 		if	(devlabel(io, READLABEL) == -1)
! 			return(-1);
! 		xpinit[io->i_ctlr][io->i_unit] = 1;
! 		}
! 	io->i_boff = lp->d_partitions[io->i_part].p_offset;
! 	return(0);
! 	}
  
+ xpclose(io)
+ 	struct	iob	*io;
+ 	{
+ 
+ 	xpinit[io->i_ctlr][io->i_unit] = 0;
+ 	return(0);
+ 	}
+ 
  xpstrategy(io, func)
  	register struct iob *io;
  {
  	int i;
  	daddr_t bn;
  	int sn, cn, tn, bae, lo16;
! 	register struct hpdevice *xpaddr = XPcsr[io->i_ctlr];
! 	register struct disklabel *lp = &io->i_label;
  
  	bn = io->i_bn;
! 	xpaddr->hpcs2.w = io->i_unit;
  
  	if ((xpaddr->hpds & HPDS_VV) == 0) {
  		xpaddr->hpcs1.c[0] = HP_PRESET|HP_GO;
  		xpaddr->hpof = HPOF_FMT22;
  	}
! 	cn = bn / lp->d_secpercyl;
! 	sn = bn % lp->d_secpercyl;
! 	tn = sn / lp->d_nsectors;
! 	sn = sn % lp->d_nsectors;
  
  	iomapadr(io->i_ma, &bae, &lo16);
  	xpaddr->hpdc = cn;
  	xpaddr->hpda = (tn << 8) + sn;
***************
*** 127,140 ****
  			continue;
  	if (xpaddr->hpcs1.w & HP_TRE) {
  		printf("xp%d,%d err cy=%d tr=%d sc=%d cs2=%o er1=%o\n",
! 		    ctlr, unit, cn, tn, sn, xpaddr->hpcs2, xpaddr->hper1);
  		return(-1);
  	}
  	return(io->i_cc);
  }
  
! xpopen(io)
  	struct iob *io;
! {
! 	return(genopen(NXP, io));
! }
--- 103,280 ----
  			continue;
  	if (xpaddr->hpcs1.w & HP_TRE) {
  		printf("xp%d,%d err cy=%d tr=%d sc=%d cs2=%o er1=%o\n",
! 		    io->i_ctlr, io->i_unit, cn, tn, sn, xpaddr->hpcs2,
! 		    xpaddr->hper1);
  		return(-1);
  	}
  	return(io->i_cc);
  }
  
! /*
!  * ALL drive type identification has been removed from the kernel's XP 
!  * driver and placed here.
!  *
!  * These tables are used to provide "the best guess" of the geometry 
!  * of the drive.  DEC RP0{4,5,6,7} and RM0{3,5} drives will match exactly.
!  * Non DEC controllers (performing an emulation) often use the DEC drive 
!  * type to mean completely different geometry/capacity drives.
! */
! 
! 	struct	xpst
! 		{
! 		int	flags;		/* flags: XP_CC, XP_NOSEARCH */
! 		int	ncyl;		/* number of cylinders */
! 		int	nspc;		/* number of sectors per cylinder */
! 		int	ntpc;		/* number of tracks per cylinder */
! 		int	nspt;		/* number of sectors per track */
! 		daddr_t	nspd;		/* number of sectors per drive */
! 		};
! 
! static struct	xpst rp04_st = { XP_CC, 411, 22 * 19, 19, 22, 411L * 22 * 19 };
! /* rp05 uses same table as rp04 */
! static struct	xpst rp06_st = { XP_CC, 815, 22 * 19, 19, 22, 815L * 22 * 19 };
! static struct	xpst rp07_st = { XP_CC, 630, 50 * 32, 32, 50, 630L * 50 * 32 };
! 
! static struct	xpst rm02_st;	/* filled in dynamically */
! static struct	xpst rm03_st = { 0, 823, 32 *  5,  5, 32, 823L * 32 *  5 };
! static struct	xpst rm05_st = { 0, 823, 32 * 19, 19, 32, 823L * 32 * 19 };
! static struct	xpst rm80_st = { 0, 559, 31 * 14, 14, 31, 559L * 31 * 14 };
! 
! /* 
!  * SI controller stuff - likely not used any longer and will probably go away
!  * eventually (when the D space is needed for something more important).
! */
! 
! static struct	xpst cdc9775_st = { 0, 843, 32 * 40, 40, 32, 843L * 32 * 40 };
! static struct	xpst cdc9730_st = { 0, 823, 32 * 10, 10, 32, 823L * 32 * 10 };
! static struct	xpst cdc9766_st = { 0, 823, 32 * 19, 19, 32, 823L * 32 * 19 };
! static struct	xpst cdc9762_st = { 0, 823, 32 *  5,  5, 32, 823L * 32 *  5 };
! static struct	xpst capric_st = { 0, 1024, 32 * 16, 16, 32, 1024L * 32 * 16 };
! static struct	xpst eagle_st   = { 0, 842, 48 * 20, 20, 48, 842L * 48 * 20 };
! 
! /*
!  * A "default".  If none of the above are useable then a default geometry
!  * suitable for writing a label (sector 1) is used.
! */
! 
! static struct	xpst default_st = { 0, 1, 2 * 1, 1, 2, 2 };
! 
! /*
!  * This routine does not return an error (-1).  If the drive is totally
!  * unrecognizeable then the default above is used.
! */
! 
! xplabel(io)
  	struct iob *io;
! 	{
! 	register struct	xpst	*st = NULL;
! 	int	type, xpsn;
! 	register struct	hpdevice *xpaddr = XPcsr[io->i_ctlr];
! 	register struct disklabel *lp;
! 
! 	type = xpaddr->hpdt & 077;
! 	switch	(type)
! 		{
! 		case	HPDT_RP04:	/* 020 */
! 		case	HPDT_RP05:	/* 021 */
! 			st = &rp04_st;
! 			break;
! 		case	HPDT_RP06:	/* 022 */
! 			st = &rp06_st;
! 			break;
! 		case	HPDT_RP07:	/* 042 */
! 			st = &rp07_st;
! 			break;
! 		case	HPDT_RM80:	/* 026 */
! 			st = &rm80_st;
! 			break;
! 		case	HPDT_RM05:	/* 027 */
! 			st = &rm05_st;
! 			break;
! 		case	HPDT_RM03:	/* 024 */
! 			st = &rm03_st;
! 			break;
! 		case	HPDT_RM02:	/* 025 */
! /*
!  * Borrowing a quote from 4BSD:  
!  *  "We know this isn't a dec controller, so we can assume sanity."
! */
! 			st = &rm02_st;
! 			xpaddr->hpcs1.w = HP_NOP;
! 			xpaddr->hpcs2.w = io->i_unit;
! 	
! 			xpaddr->rmhr = HPHR_MAXTRAK;
! 			st->ntpc = xpaddr->rmhr + 1;
! 
! 			xpaddr->rmhr = HPHR_MAXSECT;
! 			st->nspt = xpaddr->rmhr + 1;
! 
! 			xpaddr->rmhr = HPHR_MAXCYL;
! 			st->ncyl = xpaddr->rmhr + 1;
! 
! 			xpaddr->hpcs1.w = HP_DCLR | HP_GO;
! 
! 			st->nspc = st->nspt * st->ntpc;
! 			st->nspd = (long)st->nspc * st->ncyl;
! 			printf("type: RM02 c=%d t/c=%d s/t=%d\n", st->ncyl,
! 				st->ntpc, st->nspt);
! 			break;
! 		default:
! 			printf("xp%d,%d unknown drive type: %d -- ", 
! 				io->i_ctlr, io->i_unit, type);
! 			printf("using 1 cyl, 1 trk, 2 sec/trk\n");
! 			st = &default_st;
! 			break;
! 		}
! 
! /*
!  * Handle SI model byte stuff when we think it's an RM05 or RM03.  Is any
!  * one still using one of these?  Is it worth all this code?
! */
! 	if	(type == HPDT_RM05 || type == HPDT_RM03)
! 		{
! 		xpsn = xpaddr->hpsn;
! 		if	((xpsn & SIMB_LU) != io->i_unit)
! 			goto notsi;
! 		switch	((xpsn & SIMB_MB) &~ (SIMB_S6|SIRM03|SIRM05))
! 			{
! 			case	SI9775D:
! 				st = &cdc9775_st;
! 				break;
! 			case	SI9730D:
! 				st = &cdc9730_st;
! 				break;
! 			case	SI9766:
! 				st = &cdc9766_st;
! 				break;
! 			case	SI9762:
! 				st = &cdc9762_st;
! 				break;
! 			case	SICAPD:
! 				st = &capric_st;
! 				break;
! 			case	SI9751D:
! 				st = &eagle_st;
! 				break;
! 			default:
! 				printf("xp%d,%d unknown SI drive model %d -- ", 
! 					io->i_ctlr, io->i_unit, xpsn);
! 				printf("using 1 cyl, 1 trk, 2 sec/trk\n");
! 				st = &default_st;
! 				break;
! 			}
! 		}
! notsi:
! 	lp = &io->i_label;
! 	lp->d_type = DTYPE_SMD;
! 	lp->d_secsize = 512;	/* XXX */
! 	lp->d_secperunit = st->nspd;
! 	lp->d_partitions[0].p_size = st->nspd;
! 	lp->d_nsectors = st->nspt;
! 	lp->d_ntracks = st->ntpc;
! 	lp->d_secpercyl = st->nspc;
! 	lp->d_ncylinders = st->ncyl;
! 	lp->d_drivedata[0] = st->flags;
! 	strcpy(lp->d_typename, "SMD");
! 	return(0);
! 	}
*** /usr/src/sys/pdpstand/conf.c.old	Thu Jun 15 20:09:14 1995
--- /usr/src/sys/pdpstand/conf.c	Mon Jul 17 21:43:26 1995
***************
*** 3,9 ****
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)conf.c	2.3 (2.11BSD) 1995/06/15
   */
  
  #include "../h/param.h"
--- 3,9 ----
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)conf.c	2.4 (2.11BSD) 1995/07/17
   */
  
  #include "../h/param.h"
***************
*** 11,17 ****
  
  	int	nullsys();
  
! extern	int	xpstrategy(), xpopen();
  extern	int	brstrategy(), bropen();
  extern	int	rkstrategy(), rkopen();
  extern	int	hkstrategy(), hkopen();
--- 11,17 ----
  
  	int	nullsys();
  
! extern	int	xpstrategy(), xpopen(), xpclose(), xplabel();
  extern	int	brstrategy(), bropen();
  extern	int	rkstrategy(), rkopen();
  extern	int	hkstrategy(), hkopen();
***************
*** 52,59 ****
  	nullsys, nullsys,
  	"si",	sistrategy,	siopen,		nullsys,	SIcsr, /* 9 */
  	nullsys, nullsys,
! 	"xp",	xpstrategy,	xpopen,		nullsys,	XPcsr, /* 10 */
! 	nullsys, nullsys,
  	"br",	brstrategy,	bropen,		nullsys,	BRcsr, /* 11 */
  	nullsys, nullsys,
  	"tms",  tmscpstrategy,	tmscpopen,	tmscpclose,	TMScsr,/* 12 */
--- 52,59 ----
  	nullsys, nullsys,
  	"si",	sistrategy,	siopen,		nullsys,	SIcsr, /* 9 */
  	nullsys, nullsys,
! 	"xp",	xpstrategy,	xpopen,		xpclose,	XPcsr, /* 10 */
! 	xplabel, nullsys,
  	"br",	brstrategy,	bropen,		nullsys,	BRcsr, /* 11 */
  	nullsys, nullsys,
  	"tms",  tmscpstrategy,	tmscpopen,	tmscpclose,	TMScsr,/* 12 */
*** /usr/src/sys/pdpdist/disktab.old	Thu Jul 13 19:36:39 1995
--- /usr/src/sys/pdpdist/disktab	Fri Aug 18 21:56:07 1995
***************
*** 129,140 ****
  	:b0=/mdec/si94uboot:\
  	:pa#9600:oa#0:ba#1024:fa#1024:ta=2.11BSD:\
  	:pb#9600:ob#9600:bb#1024:fb#1024:tb=swap:\
! 	:pc#244002:oc#19200:bc#1024:fc#1024:tc=2.11BSD:\
! 	:pd#164800:od#19200:bd#1024:fd#1024:td=2.11BSD:\
! 	:pe#79360:oe#184000:be#1024:fe#1024:te=2.11BSD:\
! 	:pf#39680:of#184000:bf#1024:ff#1024:tf=2.11BSD:\
! 	:pg#39680:og#223680:bg#1024:fg#1024:tg=2.11BSD:\
! 	:ph#263202:bh#1024:fh#1024:th=2.11BSD
  
  diva|DIVA|9300|Diva Comp V, Ampex 9300 (in direct mode):\
  	:ty=fixed:ns#33:nt#19:nc#815:sf:\
--- 129,140 ----
  	:b0=/mdec/si94uboot:\
  	:pa#9600:oa#0:ba#1024:fa#1024:ta=2.11BSD:\
  	:pb#9600:ob#9600:bb#1024:fb#1024:tb=swap:\
! 	:pc#244160:oc#19200:bc#1024:fc#1024:tc=2.11BSD:\
! 	:pd#164800:od#19200:bd#1024:fd#1024:td=unused:\
! 	:pe#79360:oe#184000:be#1024:fe#1024:te=unused:\
! 	:pf#39680:of#184000:bf#1024:ff#1024:tf=unused:\
! 	:pg#39680:og#223680:bg#1024:fg#1024:tg=unused:\
! 	:ph#263360:oh#0:bh#1024:fh#1024:th=unused
  
  diva|DIVA|9300|Diva Comp V, Ampex 9300 (in direct mode):\
  	:ty=fixed:ns#33:nt#19:nc#815:sf:\
*** /usr/src/man/man4/xp.4.old	Wed Dec 30 14:58:00 1992
--- /usr/src/man/man4/xp.4	Tue Aug 15 20:28:30 1995
***************
*** 2,10 ****
  .\" All rights reserved.  The Berkeley software License Agreement
  .\" specifies the terms and conditions for redistribution.
  .\"
! .\"	@(#)xp.4	6.3 (2.11BSD GTE) 12/30/92
  .\"
! .TH XP 4 "September 7, 1988"
  .UC 2
  .SH NAME
  xp \- generic SMD moving-head disk
--- 2,10 ----
  .\" All rights reserved.  The Berkeley software License Agreement
  .\" specifies the terms and conditions for redistribution.
  .\"
! .\"	@(#)xp.4	6.4 (2.11BSD GTE) 1995/08/14
  .\"
! .TH XP 4 "August 14, 1995"
  .UC 2
  .SH NAME
  xp \- generic SMD moving-head disk
***************
*** 12,26 ****
  .ft B
  .nf
  /sys/conf/SYSTEM:
! .ta .5i +\w'XP_PROBE 'u +\w'xp_controllers 'u
! 	# Because the disk drive type registers conflict with other DEC
! 	# controllers, you cannot use XP_PROBE for the Ampex 9300 and
! 	# Diva drives.  Read through /sys/pdpuba/hpreg.h and /sys/pdpuba/xp.c
! 	# for information on how to initialize for these drives.
! 	NXPC	\fIxp_controllers\fP	# NXPD controllers (RH70/RH11 style)
! 	NXPD	\fIxp_drives\fP	# RM02/03/05, RP04/05/06, CDC 9766,
! 					# Ampex 9300, Diva, Fuji 160, SI Eagle.
! 	XP_PROBE	\fIYES\fP	# check drive types at boot
  .DT
  
  /etc/dtab:
--- 12,22 ----
  .ft B
  .nf
  /sys/conf/SYSTEM:
! .ta .5i +\w'BADSECT 'u +\w'xp_controllers 'u
! 	NXPC	\fIxp_controllers\fP	# Number of controllers
! 	NXPD	\fIxp_drives\fP		# RM02/03/05, RP04/05/06, 
! 					# CDC 9766, Fuji 160, etc.
! 	BADSECT	\fINO\fP		# Bad sector handling (see BUGS)
  .DT
  
  /etc/dtab:
***************
*** 34,40 ****
  	block: 10
  minor device encoding:
  	bits 0007 specify partition of XP drive
! 	bits 0070 specify XP drive
  .fi
  .ft R
  .SH DESCRIPTION
--- 30,36 ----
  	block: 10
  minor device encoding:
  	bits 0007 specify partition of XP drive
! 	bits 0370 specify XP drive
  .fi
  .ft R
  .SH DESCRIPTION
***************
*** 41,48 ****
  The
  .I xp
  driver is a generic SMD storage module disk driver.  It can be adapted to
! most SMD controllers (although bootstrapping will not necessarily be
! directly possible.)  The drives are numbered from 0 to
  .I n
  on
  controller 0, from
--- 37,44 ----
  The
  .I xp
  driver is a generic SMD storage module disk driver.  It can be adapted to
! most SMD controllers although bootstrapping will not necessarily be
! directly possible.  The drives are numbered from 0 to
  .I n
  on
  controller 0, from
***************
*** 49,56 ****
  .IR n +1
  to
  .I m
! on controller 1, etc.  The drives may have different geometries.
  .PP
  Files with minor device numbers 0 through 7 refer to various portions
  of drive 0;
  minor devices 8 through 15 refer to drive 1, etc.
--- 45,61 ----
  .IR n +1
  to
  .I m
! on controller 1, etc.  The drives may have different geometries.  
  .PP
+ The \fIxp\fP
+ driver is unique amoungst 2BSD drivers in its numbering of drives.
+ Other drivers (\fIra\fP for example) number drives 0 thru 7 on controller
+ 1, 8 thru 15 on controller 2 and so on.  \fIxp\fP on the other hand can
+ have drives 0 and 1 on controller 1, drives 2, 3, 4 and 5 on controller 2 and
+ drives 6, 7 and 8 on controller 3.  This is different from \fBboot\fP's
+ view of the world, so if you are booting from other than unit 0 you may
+ have to experiment a bit.
+ .PP
  Files with minor device numbers 0 through 7 refer to various portions
  of drive 0;
  minor devices 8 through 15 refer to drive 1, etc.
***************
*** 71,218 ****
  In raw I/O the buffer must begin on a word (even) boundary,
  and counts should be a multiple of 512 bytes (a disk sector).
  Likewise
! .I seek
  calls should specify a multiple of 512 bytes.
  .SH "DISK SUPPORT"
! If the option
! .B XP_PROBE
! is selected the driver interrogates the controller's drive type register
! to determine the type of drive attached.  The driver recognizes the
! following drives automatically:  RM02/03/05 (the CDC 9766 is recognized
! as an RM05), SI 9775, RP04/05/06, Fuji 160, Capricorn and SI Eagle.  The
! following drives are also supported, but must either be patched at boot
! time or initialized at compile time: Ampex 9300 in direct mode and DIVA
! Comp V.
  .PP
- The origin and size (in sectors) of the pseudo-disks on each drive are as
- follows:
- .nf
- .ta .5i +\w'disk  'u +\w'0000000  'u +\w'0000000  'u +\w'000 - 0000  'u
- .PP
- .ne 10
- RP04/05 partitions:
- 	disk	 start	 length	      cyls	comments
- 	xp?a	     0	   9614	  0 -   22	/
- 	xp?b	  9614	   8778	 23 -   43	swap
- 	xp?c	 18392	 153406	 44 -  410*	/usr
- 	xp?d	unusable
- 	xp?e	unusable
- 	xp?f	unused
- 	xp?g	     0	 171798	  0 -  410*	whole pack
- 	xp?h	unusable
- .PP
- .ne 10
- RP06 partitions:
- 	disk	 start	 length	      cyls	comments
- 	xp?a	     0	   9614	  0 -   22	/
- 	xp?b	  9614	   8778	 23 -   43	swap
- 	xp?c	 18392	 153406	 44 -  410	/usr
- 	xp?d	171798	 168872	411 -  814*
- 	xp?e	 18392	 322278	 44 -  814*	
- 	xp?f	unused
- 	xp?g	     0	 171798	  0 -  410
- 	xp?h	     0	 340670	  0 -  814*	whole pack
- .PP
- .ne 10
- RM02/RM03 partitions:
- 	disk	 start	 length	      cyls	comments
- 	xp?a	     0	   9600	  0 -   59	/
- 	xp?b	  9600	   9600	 60 -  119	swap
- 	xp?c	     0	 131680	  0 -  822*	whole pack + bad144 track
- 	xp?d	unused
- 	xp?e	unused
- 	xp?f	unused
- 	xp?g	 19200	 112320	120 -  821
- 	xp?h         0	 131520   0 -  821	whole pack - bad144 track
- .PP
- .ne 10
- RM05 (or SI 9500, CDC 9766) partitions:
- 	disk	 start	 length	      cyls	comments
- 	xp?a	     0	   9120	  0 -   14	/
- 	xp?b	  9120	   9120	 15 -   29	swap
- 	xp?c	 18240	 234080	 30 -  414
- 	xp?d	252320	 248064	415 -  822*
- 	xp?e	 18240	 164160	 30 -  299	/usr
- 	xp?f	182400	 152000	300 -  549
- 	xp?g	334400	 165984	550 -  822*
- 	xp?h	     0	 500384	  0 -  822*	whole pack
- .PP
- .ne 10
- Capricorn partitions:
- 	disk	 start	 length	      cyls	comments
- 	xp?a	     0	  16384	  0 -   31	/
- 	xp?b	 16384	  33792	 32 -   97	swap
- 	xp?c	 50176	 291840	 98 -  667	/usr
- 	xp?d	342016	  16384	668 -  699
- 	xp?e	358400	  56320	700 -  809
- 	xp?f	414720	 109568	810 - 1023*
- 	xp?g	342016	 182272	668 - 1023*
- 	xp?h	     0	 524288	  0 - 1023*	whole pack
- .PP
- .ne 10
- SI, CDC 9775 (direct) partitions:
- 	disk	 start	 length	      cyls	comments
- 	xp?a	     0	  10240	  0 -    7	/
- 	xp?b	 10240	  10240	  8 -   15	swap
- 	xp?c	 20480	 510720	 16 -  414
- 	xp?d	531200	 547840	415 -  842*
- 	xp?e	 20480	 363520	 16 -  299	/usr
- 	xp?f	384000	 320000	300 -  549
- 	xp?g	704000	 375040	550 -  842*
- 	xp?h	     0	1079040	  0 -  842*	whole pack
- .PP
- .ne 10
- SI 6100, Fuji Eagle 2351A partitions:
- 	disk	 start	 length	      cyls	comments
- 	xp?a	     0	  11520	  0 -   11	/
- 	xp?b	  9600	  11520	 12 -   23	swap
- 	xp?c	 19200	 474240	 24 -  517
- 	xp?d	 19200	  92160	518 -  613	/usr
- 	xp?e	144640	 218880	614 -  841*
- 	xp?f	unused
- 	xp?g	unused
- 	xp?h	     0	 808320	  0 -  841*	whole pack
- .PP
- .ne 10
- Emulex SC01B or SI 9400, Fuji 160 partitions:
- 	disk	 start	 length	      cyls	comments
- 	xp?a	     0	   9600	  0 -   29	/
- 	xp?b	  9600	   9600	 30 -   59	swap
- 	xp?c	 19200	 244160	 60 -  822*
- 	xp?d	 19200	 125440	 60 -  451	/usr
- 	xp?e	144640	 118720	452 -  822*
- 	xp?f	144640	  59520	452 -  637
- 	xp?g	204160	  59200	638 -  822*
- 	xp?h	     0	 263360	  0 -  822*	whole pack
- .PP
- .ne 10
- Diva Comp V, Ampex 9300 partitions:
- 	disk	 start	 length	      cyls	comments
- 	xp?a	     0	   9405	  0 -   14	/
- 	xp?b	  9405	   9405	 15 -   29	swap
- 	xp?c	 18810	 241395	 30 -  414
- 	xp?d	260205	 250800	415 -  814*
- 	xp?e	 18810	 169290	 30 -  299	/usr
- 	xp?f	188100	 156750	300 -  549
- 	xp?g	313500	 166155	550 -  814*
- 	xp?h	     0	 511005	  0 -  814*	whole pack
- .DT
- .fi
- .PP
- Those partitions marked with an asterisk (``*'') allow access to bad block
- information stored at the end of some packs.  Extreme care must be taken when
- creating file systems on these partitions to avoid overwriting any bad block
- information present.  In general it's best to use
- .IR newfs (8)
- to create file systems since it uses the ``safe'' partition sizes recored in
- .IR /etc/disktab .
- .PP
  Special files should only be created for the
  partitions that are actually used,
  as the overlap in these addresses could lead to confusion otherwise.
! The xp?a partition is normally used for the root file system,
  the xp?b partition as a swap area,
! and the xp?h partition for pack-pack copying (it maps the entire disk).
  .SH FILES
  .ta \w'/dev/MAKEDEV.local  'u
  /dev/xp[0-7][a-h]	block files
--- 76,99 ----
  In raw I/O the buffer must begin on a word (even) boundary,
  and counts should be a multiple of 512 bytes (a disk sector).
  Likewise
! .I lseek
  calls should specify a multiple of 512 bytes.
  .SH "DISK SUPPORT"
! Disks must be labeled using either the standalone \fIdisklabel\fP program
! on the boot tape or with the
! .IR disklabel (8)
! program.  The kernel no longer attempts to determine the drive type and
! geometry, instead reading this information from the disklabel.  There are
! no partition tables coded into the \fIxp\fP driver, these must be placed
! on the drive with \fIdisklabel\fP.
  .PP
  Special files should only be created for the
  partitions that are actually used,
  as the overlap in these addresses could lead to confusion otherwise.
! Traditionally
! the xp?a partition is normally used for the root file system,
  the xp?b partition as a swap area,
! and the xp?c partition for pack-pack copying (it maps the entire disk).  
  .SH FILES
  .ta \w'/dev/MAKEDEV.local  'u
  /dev/xp[0-7][a-h]	block files
***************
*** 273,284 ****
  .PP
  DEC-standard error logging should be supported.
  .PP
! The partition tables for the file systems should be read off of each
! pack, as they are never quite what any single installation would prefer,
! and this would make packs more portable.
! .PP
! If the drive types and parameters are not initialized, the
! .I xp
! driver uses drive type registers to discern the type of disk attached
! to each drive.  Because of numbering conflicts, foreign disks and/or
! controllers frequently cause this automatic recognition scheme to fail.
--- 154,162 ----
  .PP
  DEC-standard error logging should be supported.
  .PP
! The kernel uses partition 'h' to access the badblock information.  This 
! should have been 'c' except that almost all of the /etc/disktab entries
! (and thus existing systems) use 'h' for this purpose.  Unless you are
! very careful with \fIdisklabel\fP|(8) (to make certain that no data
! partition overlaps the badblock area) you should probably leave BADSECT
! undefined in the kernel config file.
*** /etc/disktab.old	Thu Jul 13 19:36:39 1995
--- /etc/disktab	Fri Aug 18 23:13:27 1995
***************
*** 129,140 ****
  	:b0=/mdec/si94uboot:\
  	:pa#9600:oa#0:ba#1024:fa#1024:ta=2.11BSD:\
  	:pb#9600:ob#9600:bb#1024:fb#1024:tb=swap:\
! 	:pc#244002:oc#19200:bc#1024:fc#1024:tc=2.11BSD:\
! 	:pd#164800:od#19200:bd#1024:fd#1024:td=2.11BSD:\
! 	:pe#79360:oe#184000:be#1024:fe#1024:te=2.11BSD:\
! 	:pf#39680:of#184000:bf#1024:ff#1024:tf=2.11BSD:\
! 	:pg#39680:og#223680:bg#1024:fg#1024:tg=2.11BSD:\
! 	:ph#263202:bh#1024:fh#1024:th=2.11BSD
  
  diva|DIVA|9300|Diva Comp V, Ampex 9300 (in direct mode):\
  	:ty=fixed:ns#33:nt#19:nc#815:sf:\
--- 129,140 ----
  	:b0=/mdec/si94uboot:\
  	:pa#9600:oa#0:ba#1024:fa#1024:ta=2.11BSD:\
  	:pb#9600:ob#9600:bb#1024:fb#1024:tb=swap:\
! 	:pc#244160:oc#19200:bc#1024:fc#1024:tc=2.11BSD:\
! 	:pd#164800:od#19200:bd#1024:fd#1024:td=unused:\
! 	:pe#79360:oe#184000:be#1024:fe#1024:te=unused:\
! 	:pf#39680:of#184000:bf#1024:ff#1024:tf=unused:\
! 	:pg#39680:og#223680:bg#1024:fg#1024:tg=unused:\
! 	:ph#263360:oh#0:bh#1024:fh#1024:th=unused
  
  diva|DIVA|9300|Diva Comp V, Ampex 9300 (in direct mode):\
  	:ty=fixed:ns#33:nt#19:nc#815:sf:\
*** /VERSION.old	Sat Aug 12 00:13:20 1995
--- /VERSION	Mon Aug 21 22:14:22 1995
***************
*** 1,4 ****
! Current Patch Level: 270
  
  2.11 BSD
  ============
--- 1,4 ----
! Current Patch Level: 271
  
  2.11 BSD
  ============