1/* Copyright 1999 Apple Computer, Inc.
2 *
3 * Generate a bsd disk label routine.
4 *    Input: open file descriptor to the device node, and
5 *           pointer to a disk label structure to fill in
6 *    Return: errno status
7 *
8 * HISTORY
9 *
10 * 24 Feb 1999 D. Markarian at Apple
11 *      Created.
12 */
13
14#include <string.h>              /* memset */
15#include <sys/types.h>           /* sys/disklabel.h */
16#include <sys/param.h>           /* NBPG */
17
18#include <sys/disk.h>            /* DKIOCGETBLOCKSIZE ioctl */
19
20#include <sys/disklabel.h>       /* struct disklabel */
21
22u_short dkcksum __P((register struct disklabel *lp));
23int dkdisklabelregenerate __P((int fd, struct disklabel * lp, int newblksize));
24
25/*
26 * The following two constants set the default block and fragment sizes.
27 * Both constants must be a power of 2 and meet the following constraints:
28 *	MINBSIZE <= GENBLKSIZE <= MAXBSIZE
29 *	sectorsize <= GENFRAGSIZE <= GENBLKSIZE
30 *	GENBLKSIZE / GENFRAGSIZE <= 8
31 */
32#define	GENFRAGSIZE   1024
33#define	GENBLKSIZE    NBPG  /* 4096 */
34
35/*
36 * Cylinder groups may have up to many cylinders. The actual
37 * number used depends upon how much information can be stored
38 * on a single cylinder. The default is to use 16 cylinders
39 * per group.
40 */
41#define	GENCPG        16
42
43/*
44 * Interleave is physical sector interleave, set up by the
45 * formatter or controller when formatting.  When interleaving is
46 * in use, logically adjacent sectors are not physically
47 * contiguous, but instead are separated by some number of
48 * sectors.  It is specified as the ratio of physical sectors
49 * traversed per logical sector.  Thus an interleave of 1:1
50 * implies contiguous layout, while 2:1 implies that logical
51 * sector 0 is separated by one sector from logical sector 1.
52 */
53#define	GENINTERLEAVE 1
54
55/*
56 * Rotational speed; # of data sectors per track.
57 */
58#define GENRPM        3600
59#define GENNSECTORS   32
60
61int dkdisklabel(int fd, struct disklabel * lp)
62{
63    return dkdisklabelregenerate(fd, lp, 0);
64}
65
66int dkdisklabelregenerate(int fd, struct disklabel * lp, int newblksize)
67{
68    /*
69     * Generate a bsd-style disk label for the specified device node.
70     */
71
72    int blksize;
73    int error;
74    int index;
75    int64_t numblks;
76
77    /* obtain the size of the media (in blocks) */
78    if ( (error = ioctl(fd, DKIOCGETBLOCKCOUNT, &numblks)) < 0 )
79        return(error);
80
81    /* obtain the block size of the media */
82    if ( (error = ioctl(fd, DKIOCGETBLOCKSIZE, &blksize)) < 0 )
83        return(error);
84
85    /* adjust the size of the media with newblksize should it be specified */
86    if (newblksize)
87    {
88        numblks = ((numblks * blksize) / newblksize);
89        blksize = newblksize;
90    }
91
92    /*
93     * clear the disk label structure and then fill in the appropriate fields;
94     * we comment out lines that are initializations to zero with //, since it
95     * is redundant work
96     */
97    memset(lp, 0, sizeof(struct disklabel));
98
99    lp->d_magic       = DISKMAGIC;        /* the magic number */
100//  lp->d_type        = 0;                /* drive type */
101//  lp->d_subtype     = 0;                /* controller/d_type specific */
102//  lp->d_typename[0] = 0;                /* type name, e.g. "eagle" */
103    /*
104     * d_packname contains the pack identifier and is returned when
105     * the disklabel is read off the disk or in-core copy.
106     * d_boot0 and d_boot1 are the (optional) names of the
107     * primary (block 0) and secondary (block 1-15) bootstraps
108     * as found in /usr/mdec.  These are returned when using
109     * getdiskbyname(3) to retrieve the values from /etc/disktab.
110     */
111//  lp->d_packname[0] = 0;                /* pack identifier */
112
113    /* disk geometry: */
114    lp->d_secsize        = blksize;       /* # of bytes per sector */
115    lp->d_nsectors       = GENNSECTORS;   /* # of data sectors per track */
116                                          /* # of tracks per cylinder */
117    if (numblks < 8*32*1024)              /* <=528.4 MB */
118        lp->d_ntracks = 16;
119    else if (numblks < 16*32*1024)        /* <=1.057 GB */
120        lp->d_ntracks = 32;
121    else if (numblks < 32*32*1024)        /* <=2.114 GB */
122        lp->d_ntracks = 54;
123    else if (numblks < 64*32*1024)        /* <=4.228 GB */
124        lp->d_ntracks = 128;
125    else                                  /* > 4.228 GB */
126        lp->d_ntracks = 255;
127                                          /* # of data cylinders per unit */
128    lp->d_ncylinders     = numblks / lp->d_ntracks / lp->d_nsectors;
129	                                  /* # of data sectors per cylinder */
130    lp->d_secpercyl      = lp->d_nsectors * lp->d_ntracks;
131    lp->d_secperunit     = numblks;       /* # of data sectors per unit */
132    /*
133     * Spares (bad sector replacements) below are not counted in
134     * d_nsectors or d_secpercyl.  Spare sectors are assumed to
135     * be physical sectors which occupy space at the end of each
136     * track and/or cylinder.
137     */
138//  lp->d_sparespertrack = 0;             /* # of spare sectors per track */
139//  lp->d_sparespercyl   = 0;             /* # of data sectors per unit */
140    /*
141     * Alternate cylinders include maintenance, replacement, configuration
142     * description areas, etc.
143     */
144//  lp->d_acylinders = 0;                 /* # of alt. cylinders per unit */
145
146    /* hardware characteristics: */
147    /*
148     * d_interleave, d_trackskew and d_cylskew describe perturbations
149     * in the media format used to compensate for a slow controller.
150     * Interleave is physical sector interleave, set up by the
151     * formatter or controller when formatting.  When interleaving is
152     * in use, logically adjacent sectors are not physically
153     * contiguous, but instead are separated by some number of
154     * sectors.  It is specified as the ratio of physical sectors
155     * traversed per logical sector.  Thus an interleave of 1:1
156     * implies contiguous layout, while 2:1 implies that logical
157     * sector 0 is separated by one sector from logical sector 1.
158     * d_trackskew is the offset of sector 0 on track N relative to
159     * sector 0 on track N-1 on the same cylinder.  Finally, d_cylskew
160     * is the offset of sector 0 on cylinder N relative to sector 0
161     * on cylinder N-1.
162     */
163    lp->d_rpm            = GENRPM;        /* rotational speed */
164    lp->d_interleave     = GENINTERLEAVE; /* hardware sector interleave */
165//  lp->d_trackskew      = 0;             /* sector 0 skew, per track */
166//  lp->d_cylskew        = 0;             /* sector 0 skew, per cylinder */
167//  lp->d_headswitch     = 0;             /* head switch time, usec */
168//  lp->d_trkseek        = 0;             /* track-to-track seek, usec */
169//  lp->d_flags          = 0;             /* generic flags */
170//  lp->d_drivedata[0-4] = 0;             /* drive-type specific information */
171//  lp->d_spare[0-4]     = 0;             /* reserved for future use */
172    lp->d_magic2         = DISKMAGIC;     /* the magic number (again) */
173//  lp->d_checksum       = 0;             /* xor of data incl. partitions */
174
175    /* filesystem and partition information: */
176    lp->d_npartitions    = MAXPARTITIONS; /* number of partitions */
177
178    for (index = 0; index < MAXPARTITIONS; index++)
179    {
180        struct partition * pp = &(lp->d_partitions[index]);
181        pp->p_size   = numblks;                         /* number of sectors */
182//      pp->p_offset = 0;                               /* starting sector */
183        pp->p_fsize  = MAX(GENFRAGSIZE, blksize);       /* fs fragment size */
184        pp->p_fstype = FS_BSDFFS;                       /* fs type */
185        pp->p_frag   = MIN(8, GENBLKSIZE / pp->p_fsize);/* fs fragments/block */
186        pp->p_cpg    = GENCPG;                          /* fs cylinders/group */
187    }
188
189    /* compute a checksum on the resulting structure */
190    lp->d_checksum = dkcksum(lp);
191
192    return 0; /* success */
193}
194