/* /usr/src/mach/utils/wrdl.c	Version 1.0
Purpose:	Create a disk label for a PC532 Mach SCSI disc.
Invocation:	./wrdl > /dev/rsd1c
Author:		jhs@ 	Released Public Domain 1-93
		Based on a simpler program of same name by gj@_ERASE_freebsd.org
		(thanks Gary).
To Do:		- Maybe convert to use /etc/disktab format later.
		- If nothing defined, create a valid disc label, 
		  but with all sizes 0.
Usage:		For a demo run, try
			cc -Djulian_663476 wrdl.c ; a.out | rddl
See Also:	gj's rddl.c (for which I merely improved the display format).
*/
/* ------------------------------------------------------------------------- */
/*  USER SPECIFIABLE DISC MODEL NAME & PARTITION SIZES - CHANGE AT WILL.
 - Standard size partitions ease partition clone copying between discs.
 - Partitions not aligned to cylinder boundaries may be slightly slower, but
 - Cylinder alignement seems to not be achievable on some SCSI discs, as
   Seagate ST4767 94601 Spec. P176 says:
	"Because of Zone Bit Recording(TM), there exists no single value for
	 sectors per track"
   It is also worth noting, the Seagate Spec. also says:
	"number of user sectors/track may be less than the reported value,
	 depending on sparing scheme selected".
 - The following optional defines may be asserted
   ( either here or from the cc command ) :
	Name		Meaning If Defined
	SHORT_KERNEL	Reduce 1st kernel by 1 sector from normal KERNEL_SIZE
			(so that 2nd kernel offset is KERNEL_SIZE).
	ONE_KERNEL	Have just 1 kernel, instead of normal 2 adjacent kernels.
	TWO_ROOTS	Have 2 adjacent roots, else just 1 normally.
	KERNEL_SIZE	Size of kernel partition (1st kernel might be 1 less)
	ROOT_SIZE	Size of root partition
	USR_SIZE	Size of usr partition (not used for usr1)
	m_Something	Generic model type attributes.
 - Model names are all either of form
	-  m_MANUFACTURER_MODEL_m_123456_p_123456,
		with first 123456 being declared size of media,
		second being declared size of C partition
		This is done because some of the entries are obviously wrong, &
		need to be corrected, but users must agree first.
	- m_MANUFACTURER_MODEL_s_123456
		where media size & C partition size are declared the same.
   Please mail jhs@ name of manufacturer & model where
   _UNKNOWN is shown.
*/

#ifdef	julian
	#define	m_MICROPOLIS_1684v7_s_663476
	#define	TWO_ROOTS
#endif			/* } */
#ifdef	jordan
	#define	m_SEAGATE_ST1480N_s_832527
	#define	TWO_ROOTS
#endif			/* } */
#ifdef	stuart
	#define	m_MICROPOLIS_1375_s_284480
#endif			/* } */
#ifdef	khe	/* { */
	#define			m_MICROPOLIS_1375_s_284480
#endif			/* } */
#ifdef	gary_288750	/* { */
	/* what used to be known as MB140, without jordan variant */
	#define			m_UNKNOWN_GARY_OR_JORDAN_TO_SAY_s_288750
	#define	SHORT_KERNEL
	#define	KERNEL_SIZE		  1025
	#define	ROOT_SIZE		 37800
	#define	USR_SIZE		 248389
	#define MB140_BACKWARD_COMPATIBLE_HACK
	#define	PARTITION_CHANGES
#endif			/* } */
#ifdef	gary_831488	/* { */
		/* Previously known to Gary's wrdl.c as MB406 */
	#define			m_UNKNOWN_GARY_TO_SAY_s_831488
	#define	SHORT_KERNEL
	#define	KERNEL_SIZE		  1025
	#define	ROOT_SIZE		120000
	#define	USR_SIZE		240000
	#define	TWO_ROOTS
	#define	PARTITION_CHANGES
#endif			/* } */
#ifdef	gary_1006016	/* { */
		/* Previously known as MB503 */
	#define			m_UNKNOWN_GARY_TO_SAY_s_1006016
	#define	SHORT_KERNEL
	#define	KERNEL_SIZE		 10560
	#define	ROOT_SIZE		119680
	#define	USR_SIZE		239360
	#define	TWO_ROOTS
	#define	PARTITION_CHANGES
#endif			/* } */
/* -------------------------------------------------------------------------
	If you'r using a drive type somebody else has already defined,
	you May not need to edit anything else in this file,
	However some old entries still have partition sizes hard-coded in !
	(see PARTITION_CHANGES), & some have (CAPACITY_DISPARITY entries)
   -------------------------------------------------------------------------
   GENERIC DEFAULT PREFERENCES - DO NOT CHANGE THESE
   (unless you are review all entries above also)
*/
#ifndef	KERNEL_SIZE	/* { */
	#define	KERNEL_SIZE	  1280
#endif			/* } */
#ifndef	ROOT_SIZE	/* { */
	#define	ROOT_SIZE	 60000
#endif			/* } */
#ifndef	USR_SIZE	/* { */
	#define	USR_SIZE	120000
#endif			/* } */
/* ------------------------------------------------------------------------- */
/* Device driver minor inode number offsets - do not change order
   ( because although offsets are taken explicitly from here,
	other code in this file also assumes the same ordering) */
#define	MINOR_0A_ROOT1		0	/* Partition # 4		*/
#define	MINOR_1B_ROOT2		1	/* Partition # 5 (optional)	*/
#define	MINOR_2C_TOTAL		2	/* Whole Disc			*/
#define	MINOR_3D_USR		3	/* Partition # 6		*/
#define	MINOR_4E_USR1		4	/* Partition # 7 (optional)	*/
#define	MINOR_5F_DISKLABEL	5	/* Partition # 1		*/
#define	MINOR_6G_KERNEL1	6	/* Partition # 2		*/
#define	MINOR_7H_KERNEL2	7	/* Partition # 3 (optional)	*/
/* ------------------------------------------------------------------------- */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include "../dl.h"

#define BYTES_PER_SECTOR	512
unsigned char sector[BYTES_PER_SECTOR] ;
u_long	remainder ;		/* unallocated sectors */
char	**ARGV ;		/* name of program */

/* Tell it how many sectors you want, it returns same number, if available,
   or maybe somewhat less, or 0 if [none left or none requested]
   (remember amount we want may be 0 for alternate root size)
*/
	u_long
sec_alloc(want,name)
	u_long	want ;
	char*	name ;
	{
	if ( want <= remainder )	{ remainder -= want ; return(want) ; }
	fprintf(stderr,"%s: Warning %s partition size only %ld, not %ld.\n",
		*ARGV, name, (long)remainder, (long)want) ;
	want = remainder ;
	remainder = (u_long)0 ;
	return(want) ;
	}

main(argc,argv,envp)
	int argc ;
	char **argv ;
	char **envp ;
	{
	struct disklabel *dl ;
	int	fd ;
	int	bytes ;
	int	count ;

	ARGV			= argv ;
	dl			= (struct disklabel *)&sector [LABELOFFSET] ;
	dl->d_magic		= dl->d_magic2	= DISKMAGIC ;
	dl->d_type		= DTYPE_SCSI ;
	strcpy(dl->d_typename,"SCSI") ;
	dl->d_secsize		= (long)BYTES_PER_SECTOR ;
#define	EIGHT	8
	dl->d_npartitions	= EIGHT ;

/* ------------------------------------------------------------------------- */
#define	SIZE_DISKLABEL	1
#ifdef	SHORT_KERNEL	/* { */
	#define	SIZE_KERNEL1		( KERNEL_SIZE - 1 )
#else			/* }{ */
	#define	SIZE_KERNEL1		KERNEL_SIZE
#endif			/* } */
#ifdef	ONE_KERNEL		/* { One kernel space */
	#define	SIZE_KERNEL2		0
#else				/* }{ Two Kernel spaces */
	#define	SIZE_KERNEL2		KERNEL_SIZE
#endif				/* } */
#ifdef	TWO_ROOTS		 /* { Devote space for a spare emergency root */
	#define	SIZE_ROOT2		ROOT_SIZE
#else				 /* }{ No spare root, Probably a small disc, */
	#define	SIZE_ROOT2		0
#endif				/* } */
/* ------------------------------------------------------------------------- */
	/* GENERIC PARAMETERS
	   Some default values.
	   Note, Where values are known for certain for a specific disk,
	   they should be repeated in that #ifdef entry,
	   thus protecting against possible change of defaults.
	 */
	dl->d_rpm		= 3600 ;
	dl->d_interleave	= 1 ;
	dl->d_cylskew		= 0 ;
	dl->d_trackskew		= 0 ;
	dl->d_headswitch	= 0 ;	/* head switch time, usec */
	dl->d_trkseek		= 5000 ;
	dl->d_acylinders	= 3 ;
	/* I initialise to 1 here, because if we let C compiler init to 0,
	   when Mach boots, something does a divide by zero, & boot fails.
	   Init to 1 here means if we dont know specific values we dont have to 
	   set arbitrary dummy values */
	dl->d_nsectors = dl->d_sparespertrack = dl->d_ntracks =
	dl->d_ncylinders = dl->d_rpm  = 1 ;

/* ------------------------------------------------------------------------- */
	/* START OF: DISC MODEL NUMBER DEPENDENT GENERIC PARAMETERS
	    Shouldnt need to be changed,
	    unless the low level format utility (in the eprom of
	    disc controller card, or scsi analyser) has invoked a format
	    with non standard parameters
	    (No aggregate parameters here, such as
		dl->d_sparespercyl, dl->d_secpercyl, dl->d_secperunit )
	 */

#ifdef	m_MICROPOLIS_1375_s_284480
	/* { values from jhs@		142 MB 284480 sectors */
	dl->d_nsectors		= 35 ;	/* 35 data + 1 spare, probably */
	dl->d_sparespertrack	= 1 ;
	dl->d_ntracks		= 8 ;
	dl->d_ncylinders	= 1016 ;
	dl->d_rpm		= 3600 ;
	#define			CAPACITY_DISPARITY
	#define			MODEL_DEFINED
#endif			/* } */
#ifdef	m_UNKNOWN_GARY_OR_JORDAN_TO_SAY_s_288750 /* { */
	dl->d_nsectors		= 35 ;
	dl->d_ntracks		= 10 ;
	dl->d_ncylinders	= 830 ;
	dl->d_sparespertrack	= 1 ;
	dl->d_acylinders	= 5 ;
	#define			CAPACITY_DISPARITY
	#define			MODEL_DEFINED
#endif			/* } */
#ifdef	m_MICROPOLIS_1684v7_s_663476	/* { */
	dl->d_nsectors		= 54 ;
	dl->d_ntracks		= 7 ;
	dl->d_ncylinders	= 1776 ;
	#define			CAPACITY_DISPARITY
	#define			MODEL_DEFINED
#endif			/* } */
#ifdef	m_UNKNOWN_GARY_TO_SAY_s_831488		/* { */
	dl->d_nsectors		= 62 ;
	dl->d_ntracks		= 9 ;
	dl->d_ncylinders	= 1476 ;
	dl->d_sparespertrack	= 1 ;
	dl->d_acylinders	= 2 ;
	#define			CAPACITY_DISPARITY
	#define			MODEL_DEFINED
#endif			/* } */
#ifdef	m_UNKNOWN_GARY_TO_SAY_s_1006016		/* { */
	dl->d_nsectors		= 64 ;
	dl->d_ntracks		= 11 ;
	dl->d_ncylinders	= 1429 ;
	dl->d_sparespertrack	= 1 ;
	dl->d_acylinders	= 2 ;
	#define			CAPACITY_DISPARITY
	#define			MODEL_DEFINED
#endif			/* } */
#ifdef	m_SEAGATE_ST4767N_s_1299840	/* { values from jhs@ */
	dl->d_ntracks		= 15 ;	/* Seagate info. */
	dl->d_rpm		= 4800 ;/* Seagate info. */
	dl->d_sparespertrack	= 1 ;	/* Seagate 94601 Spec. P174 */
	dl->d_interleave	= 1 ;	/* Seagate 94601 Spec. P174 */
	dl->d_cylskew		= 0x16;	/* Seagate 94601 Spec. P174 */
	dl->d_trackskew		= 0xC ;	/* Seagate 94601 Spec. P174 */
	dl->d_trkseek		= 2500 ;	/* Seagate Sales Leaflet */
	dl->d_acylinders	= 2 ;	/* Seagate sample Page 15 94601 Spec. */
	/* Suspect values below */
	dl->d_ncylinders	= 1356	/* 1356 is Seagate info. */	-
					dl->d_acylinders ;
	dl->d_nsectors		= 71 - dl->d_sparespertrack ;	/* 70 */
		/* Seagate 94601 Spec. P176 says:
			number of user sectors/track may be less than the
			reported value, depending onsparing scheme selected
		*/
	#define			CAPACITY_DISPARITY
	#define			MODEL_DEFINED
#endif		/* } */
#ifdef	m_SEAGATE_ST1096N	/* { arbitrary dummy figures */
	#define			CAPACITY_DISPARITY
	#define			MODEL_DEFINED
#endif		/* } */
#ifdef	m_SEAGATE_ST1480N_s_832527
	#define			CAPACITY_DISPARITY
	#define			MODEL_DEFINED
#endif		/* } */
#ifndef MODEL_DEFINED	/* { */
	This uncommented text is to enable the compiler to detect that
	you have failed to select a disc model type ;
#endif		/* } */
/* ------------------------------------------------------------------------- */
	/* Calculate aggregate parameters here. */
	dl->d_sparespercyl	= dl->d_sparespertrack * dl->d_ntracks ;
	dl->d_secpercyl		= dl->d_nsectors * dl->d_ntracks ;
		 /* how many sectors should be in a disc */
	dl->d_secperunit	= (dl->d_secpercyl - dl->d_sparespercyl) *
				  ( dl->d_ncylinders - dl->d_acylinders) ;
	/* Note this dl->d_secperunit never seems to be what we get
		in fact */
	dl->d_partitions[MINOR_2C_TOTAL].p_size = 0 ;	/* mark as unset */
/* ------------------------------------------------------------------------- */
#ifdef	CAPACITY_DISPARITY	/* { */
	/*    - Usually the theoretical number of sectors on a disc does not
		concur with what is actually available,
		hence this CAPACITY_DISPARITY ifdef.
	      - To find a disc's actual capacity, do a hard reformat,
		write a much-larger-than-expected disc label, then do a
		raw read of the whole disc with dd & note record count.
		( dd if=/dev/rsd0c of=/dev/null )
	      - The reason jordan's totals are less than disc should
		provide, is that he often guessed a capacity, then rounded
		down, rather than wait for a dd capacity test to run.
	*/
#ifdef	m_MICROPOLIS_1375_s_284480
	dl->d_secperunit =				284480 ;
	#define	DISPARITY_DEFINED
#endif			/* } */
#ifdef	m_UNKNOWN_GARY_OR_JORDAN_TO_SAY_s_288750 /* { */
	dl->d_secperunit =  				288750 ; /* 825 * 350 */ ;
	dl->d_partitions[MINOR_2C_TOTAL].p_size =
							288749 ;
	#define	DISPARITY_DEFINED
#endif			/* } */
#ifdef	m_UNKNOWN_JORDAN_TO_SAY_m_831488_p_335789	/* { */
	dl->d_secperunit =				831488 ;
	dl->d_partitions[MINOR_2C_TOTAL].p_size =	335789 ;
	#define	DISPARITY_DEFINED
#endif			/* } */
#ifdef	m_UNKNOWN_GARY_TO_SAY_s_831488	/* { */
	dl->d_secpercyl	=				   350 ;
	dl->d_secperunit = dl->d_partitions[MINOR_2C_TOTAL].p_size = 831488 ;
	#define	DISPARITY_DEFINED
#endif			/* } */
#ifdef	m_UNKNOWN_GARY_TO_SAY_s_1006016	/* { */
	dl->d_secperunit =				1006016 ;
	#define	DISPARITY_DEFINED
#endif			/* } */
#ifdef	m_MICROPOLIS_1684v7_s_663476	/* { */
	dl->d_secperunit =				663476 ;
		/* values from jhs@ after format by adaptec 1542b */
	#define	DISPARITY_DEFINED
#endif			/* } */
#ifdef	m_SEAGATE_ST4767N_s_1299840		/* { values from jhs@ */
	dl->d_secperunit	= 1299840 ; /* 665,518,080 bytes */
	/* Theoretically 1,421,700 sectors.
	Seagate products guide says 676M @ 512 bytes/sector.
	These
		dl->d_sparespercyl	and	dl->d_secpercyl
	are not used below, ( and not used by the kernel,
	so I've been told, ) so not bothering to set these.
	*/
	#define	DISPARITY_DEFINED
#endif			/* } */
#ifdef	m_SEAGATE_ST1480N_s_832527
	dl->d_secperunit	= 832527 ; 
	#define	DISPARITY_DEFINED
#endif			/* } */
#ifdef			m_SEAGATE_ST1096N 
	dl->d_secperunit	= 180000 ; /* initial guess */
	#define	DISPARITY_DEFINED
/* stuart currently configured by gary as:
d_type: 4       ( DTYPE_SCSI is 4 )
d_typename:     SCSI
d_secsize:      512
d_npartitions:  8
d_nsectors:     70
d_ntracks:      15
d_ncylinders:   1354
d_secpercyl:    1050
d_secperunit:   180000
d_sparespertrack:       1
d_sparespercyl: 15
d_acylinders:   2
d_rpm:          4800
d_interleave:   1
d_trackskew:    12
d_cylskew:      22
d_headswitch:   0
d_trkseek:      2500
d_npartitions:  8
[0=a]:  size   60000,  offset    2561,  Root
[1=b]:  size       0,  offset       0,  Alternate Root
[2=c]:  size  180000,  offset       0,  Whole Disc
[3=d]:  size  117439,  offset   62561,  Usr
[4=e]:  size       0,  offset       0,  Usr1
[5=f]:  size       1,  offset       0,  Disc Label
[6=g]:  size    1280,  offset       1,  First Kernel
[7=h]:  size    1280,  offset    1281,  Second Kernel
*/
#endif			/* } */
#ifndef	DISPARITY_DEFINED	/* { */
	This uncommented text is to enable the compiler to detect that
	you have specified CAPACITY_DISPARITY, but that no disparity
	information was found for the appropriate m_Something;
#endif	/* DISPARITY_DEFINED } */
#endif	/* CAPACITY_DISPARITY } */
/* ------------------------------------------------------------------------- */
	/* Check if we have a finite size disc to allocate */
	if (dl->d_secperunit == 0)
		{
		fprintf(stderr,
		  "%s: Fatal Error, program compiled with no disc defined.\n",
				*ARGV) ;
		exit(1) ;
		}

	/* allocate disk slices */
	if (dl->d_partitions[MINOR_2C_TOTAL].p_size == 0)
		/* if no special fix above, make c partition = media size */
		dl->d_partitions[MINOR_2C_TOTAL].p_size = dl->d_secperunit ;
	remainder = dl->d_partitions[MINOR_2C_TOTAL].p_size ;
	dl->d_partitions[MINOR_2C_TOTAL].p_offset = 0 ;

	dl->d_partitions[MINOR_5F_DISKLABEL].p_offset = 0 ;
	dl->d_partitions[MINOR_5F_DISKLABEL].p_size =
		sec_alloc( SIZE_DISKLABEL,"Disc Label") ;

	dl->d_partitions[MINOR_6G_KERNEL1].p_offset =
		dl->d_partitions[MINOR_5F_DISKLABEL].p_offset +
		dl->d_partitions[MINOR_5F_DISKLABEL].p_size ;
	dl->d_partitions[MINOR_6G_KERNEL1].p_size =
		sec_alloc( SIZE_KERNEL1,"First Kernel") ;

	dl->d_partitions[MINOR_7H_KERNEL2].p_offset =
		dl->d_partitions[MINOR_6G_KERNEL1].p_offset +
		dl->d_partitions[MINOR_6G_KERNEL1].p_size ;
	dl->d_partitions[MINOR_7H_KERNEL2].p_size =
		sec_alloc( SIZE_KERNEL2,"Second Kernel") ;

	dl->d_partitions[MINOR_0A_ROOT1].p_offset =
		dl->d_partitions[MINOR_7H_KERNEL2].p_offset +
		dl->d_partitions[MINOR_7H_KERNEL2].p_size ;
#ifdef MB140_BACKWARD_COMPATIBLE_HACK	/* { */
	/* Urgh - This is a weird config.
	Kernels of 1025 and a root offset at 2*1280 - why ?
	I suggest whoever has this do this :
	Invoke rom monitor or dd (on /dev/...c) to move 2nd kernel up a bit,
	Increase KERNEL_SIZE to 1280,
	Recompile & create new disklabel
	PLEASE Mail jhs@ when this ifdef can be deleted.
	*/
	dl->d_partitions[MINOR_0A_ROOT1].p_offset = 2*1280 ;
#endif						/* } */
	dl->d_partitions[MINOR_0A_ROOT1].p_size =
		sec_alloc(ROOT_SIZE, "Root") ;

	dl->d_partitions[MINOR_1B_ROOT2].p_offset =
		dl->d_partitions[MINOR_0A_ROOT1].p_offset +
		dl->d_partitions[MINOR_0A_ROOT1].p_size ;
	dl->d_partitions[MINOR_1B_ROOT2].p_size =
		sec_alloc( SIZE_ROOT2,"Alternate Root") ;

	dl->d_partitions[MINOR_3D_USR].p_offset =
		dl->d_partitions[MINOR_1B_ROOT2].p_offset +
		dl->d_partitions[MINOR_1B_ROOT2].p_size ;
	dl->d_partitions[MINOR_3D_USR].p_size =
		sec_alloc( USR_SIZE,"Usr") ;

	/* All/any remaining space gets allocated here */
	dl->d_partitions[MINOR_4E_USR1].p_offset =
		dl->d_partitions[MINOR_3D_USR].p_offset +
		dl->d_partitions[MINOR_3D_USR].p_size ;
	dl->d_partitions[MINOR_4E_USR1].p_size = remainder ;

/* ------------------------------------------------------------------------- */
#ifdef	PARTITION_CHANGES /* { */
	/* PARTITION MODIFICATIONS for old configurations,
	   Kept only for compatability.
	   The program has by now automatically calculated the correct value
	   for MINOR_4E_USR1 p_size & p_offset, so the values forced below
	   either waste space or reach beyond the end of physical disk.
	   The reason for these anomalous values is presumably one of:
		- Bad manual calculation
		- Segments of disc being reserved for other usage
		  (possibly in Gary's case because one of his SCSI disks
		  has a large physically damaged area).
	 */
#ifdef	jordan_288750	/* { */
	dl->d_partitions[MINOR_4E_USR1].p_size = 0 ;
	#define	PARTITION_CHANGE_DEFINED
#endif			/* } */
#ifdef	gary_288750	/* { */
	dl->d_partitions[MINOR_4E_USR1].p_size = 125000 ;
	dl->d_partitions[MINOR_4E_USR1].p_offset = 159900 ;
	#define	PARTITION_CHANGE_DEFINED
#endif			/* } */
#ifdef	gary_831488	/* { */
	dl->d_partitions[MINOR_4E_USR1].p_size = 349438 ;
	#define	PARTITION_CHANGE_DEFINED
#endif			/* } */
#ifdef	jordan_335789	/* { */
	dl->d_partitions[MINOR_4E_USR1].p_size = 0 ;
	#define	PARTITION_CHANGE_DEFINED
#endif			/* } */
#ifdef	gary_1006016	/* { */
	dl->d_partitions[MINOR_4E_USR1].p_size = 506176 ;
	#define	PARTITION_CHANGE_DEFINED
#endif			/* } */
#ifndef	 PARTITION_CHANGE_DEFINED	/* { */
	This uncommented text is to enable the compiler to detect that
	no PARTITION_CHANGES are specified for OWNER ;
#endif	/* } */
#endif	/* } */
/* ------------------------------------------------------------------------- */
/* Cosmetics, so disk label will look exactly the same as a hand made label */
for (count = 0 ; count < EIGHT ; count++ )
	if ( dl->d_partitions[count].p_size == 0 )
		dl->d_partitions[count].p_offset = 0 ;
/* ------------------------------------------------------------------------- */
	if ((bytes=write(1, sector, BYTES_PER_SECTOR)) != BYTES_PER_SECTOR)
		{
		fprintf(stderr,"%s: Only wrote %d bytes, not %d.\n",
			*ARGV,bytes,BYTES_PER_SECTOR) ;
		exit (1) ;
		}
	}

