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 ============