1*433d6423SLionel Sambuc /* IBM device driver utility functions. Author: Kees J. Bot
2*433d6423SLionel Sambuc * 7 Dec 1995
3*433d6423SLionel Sambuc * Entry point:
4*433d6423SLionel Sambuc * partition: partition a disk to the partition table(s) on it.
5*433d6423SLionel Sambuc */
6*433d6423SLionel Sambuc
7*433d6423SLionel Sambuc #include <minix/blockdriver.h>
8*433d6423SLionel Sambuc #include <minix/drvlib.h>
9*433d6423SLionel Sambuc #include <unistd.h>
10*433d6423SLionel Sambuc
11*433d6423SLionel Sambuc /* Extended partition? */
12*433d6423SLionel Sambuc #define ext_part(s) ((s) == 0x05 || (s) == 0x0F)
13*433d6423SLionel Sambuc
14*433d6423SLionel Sambuc static void parse_part_table(struct blockdriver *bdp, int device,
15*433d6423SLionel Sambuc int style, int atapi, u8_t *tmp_buf);
16*433d6423SLionel Sambuc
17*433d6423SLionel Sambuc static void extpartition(struct blockdriver *bdp, int extdev,
18*433d6423SLionel Sambuc unsigned long extbase, u8_t *tmp_buf);
19*433d6423SLionel Sambuc
20*433d6423SLionel Sambuc static int get_part_table(struct blockdriver *bdp, int device,
21*433d6423SLionel Sambuc unsigned long offset, struct part_entry *table, u8_t *tmp_buf);
22*433d6423SLionel Sambuc
23*433d6423SLionel Sambuc static void sort(struct part_entry *table);
24*433d6423SLionel Sambuc
25*433d6423SLionel Sambuc /*============================================================================*
26*433d6423SLionel Sambuc * partition *
27*433d6423SLionel Sambuc *============================================================================*/
partition(struct blockdriver * bdp,int device,int style,int atapi)28*433d6423SLionel Sambuc void partition(
29*433d6423SLionel Sambuc struct blockdriver *bdp, /* device dependent entry points */
30*433d6423SLionel Sambuc int device, /* device to partition */
31*433d6423SLionel Sambuc int style, /* partitioning style: floppy, primary, sub. */
32*433d6423SLionel Sambuc int atapi /* atapi device */
33*433d6423SLionel Sambuc )
34*433d6423SLionel Sambuc {
35*433d6423SLionel Sambuc /* This routine is called on first open to initialize the partition tables
36*433d6423SLionel Sambuc * of a device.
37*433d6423SLionel Sambuc */
38*433d6423SLionel Sambuc u8_t *tmp_buf;
39*433d6423SLionel Sambuc
40*433d6423SLionel Sambuc if ((*bdp->bdr_part)(device) == NULL)
41*433d6423SLionel Sambuc return;
42*433d6423SLionel Sambuc
43*433d6423SLionel Sambuc /* For multithreaded drivers, multiple partition() calls may be made on
44*433d6423SLionel Sambuc * different devices in parallel. Hence we need a separate temporary buffer
45*433d6423SLionel Sambuc * for each request.
46*433d6423SLionel Sambuc */
47*433d6423SLionel Sambuc if (!(tmp_buf = alloc_contig(CD_SECTOR_SIZE, AC_ALIGN4K, NULL)))
48*433d6423SLionel Sambuc panic("partition: unable to allocate temporary buffer");
49*433d6423SLionel Sambuc
50*433d6423SLionel Sambuc parse_part_table(bdp, device, style, atapi, tmp_buf);
51*433d6423SLionel Sambuc
52*433d6423SLionel Sambuc free_contig(tmp_buf, CD_SECTOR_SIZE);
53*433d6423SLionel Sambuc }
54*433d6423SLionel Sambuc
55*433d6423SLionel Sambuc /*============================================================================*
56*433d6423SLionel Sambuc * parse_part_table *
57*433d6423SLionel Sambuc *============================================================================*/
parse_part_table(struct blockdriver * bdp,int device,int style,int atapi,u8_t * tmp_buf)58*433d6423SLionel Sambuc static void parse_part_table(
59*433d6423SLionel Sambuc struct blockdriver *bdp, /* device dependent entry points */
60*433d6423SLionel Sambuc int device, /* device to partition */
61*433d6423SLionel Sambuc int style, /* partitioning style: floppy, primary, sub. */
62*433d6423SLionel Sambuc int atapi, /* atapi device */
63*433d6423SLionel Sambuc u8_t *tmp_buf /* temporary buffer */
64*433d6423SLionel Sambuc )
65*433d6423SLionel Sambuc {
66*433d6423SLionel Sambuc /* This routine reads and parses a partition table. It may be called
67*433d6423SLionel Sambuc * recursively. It makes sure that each partition falls safely within the
68*433d6423SLionel Sambuc * device's limits. Depending on the partition style we are either making
69*433d6423SLionel Sambuc * floppy partitions, primary partitions or subpartitions. Only primary
70*433d6423SLionel Sambuc * partitions are sorted, because they are shared with other operating
71*433d6423SLionel Sambuc * systems that expect this.
72*433d6423SLionel Sambuc */
73*433d6423SLionel Sambuc struct part_entry table[NR_PARTITIONS], *pe;
74*433d6423SLionel Sambuc int disk, par;
75*433d6423SLionel Sambuc struct device *dv;
76*433d6423SLionel Sambuc unsigned long base, limit, part_limit;
77*433d6423SLionel Sambuc
78*433d6423SLionel Sambuc /* Get the geometry of the device to partition */
79*433d6423SLionel Sambuc if ((dv = (*bdp->bdr_part)(device)) == NULL
80*433d6423SLionel Sambuc || dv->dv_size == 0) return;
81*433d6423SLionel Sambuc base = (unsigned long)(dv->dv_base / SECTOR_SIZE);
82*433d6423SLionel Sambuc limit = base + (unsigned long)(dv->dv_size / SECTOR_SIZE);
83*433d6423SLionel Sambuc
84*433d6423SLionel Sambuc /* Read the partition table for the device. */
85*433d6423SLionel Sambuc if(!get_part_table(bdp, device, 0L, table, tmp_buf)) {
86*433d6423SLionel Sambuc return;
87*433d6423SLionel Sambuc }
88*433d6423SLionel Sambuc
89*433d6423SLionel Sambuc /* Compute the device number of the first partition. */
90*433d6423SLionel Sambuc switch (style) {
91*433d6423SLionel Sambuc case P_FLOPPY:
92*433d6423SLionel Sambuc device += MINOR_fd0p0;
93*433d6423SLionel Sambuc break;
94*433d6423SLionel Sambuc case P_PRIMARY:
95*433d6423SLionel Sambuc sort(table); /* sort a primary partition table */
96*433d6423SLionel Sambuc device += 1;
97*433d6423SLionel Sambuc break;
98*433d6423SLionel Sambuc case P_SUB:
99*433d6423SLionel Sambuc disk = device / DEV_PER_DRIVE;
100*433d6423SLionel Sambuc par = device % DEV_PER_DRIVE - 1;
101*433d6423SLionel Sambuc device = MINOR_d0p0s0 + (disk * NR_PARTITIONS + par) * NR_PARTITIONS;
102*433d6423SLionel Sambuc }
103*433d6423SLionel Sambuc
104*433d6423SLionel Sambuc /* Find an array of devices. */
105*433d6423SLionel Sambuc if ((dv = (*bdp->bdr_part)(device)) == NULL) return;
106*433d6423SLionel Sambuc
107*433d6423SLionel Sambuc /* Set the geometry of the partitions from the partition table. */
108*433d6423SLionel Sambuc for (par = 0; par < NR_PARTITIONS; par++, dv++) {
109*433d6423SLionel Sambuc /* Shrink the partition to fit within the device. */
110*433d6423SLionel Sambuc pe = &table[par];
111*433d6423SLionel Sambuc part_limit = pe->lowsec + pe->size;
112*433d6423SLionel Sambuc if (part_limit < pe->lowsec) part_limit = limit;
113*433d6423SLionel Sambuc if (part_limit > limit) part_limit = limit;
114*433d6423SLionel Sambuc if (pe->lowsec < base) pe->lowsec = base;
115*433d6423SLionel Sambuc if (part_limit < pe->lowsec) part_limit = pe->lowsec;
116*433d6423SLionel Sambuc
117*433d6423SLionel Sambuc dv->dv_base = (u64_t)pe->lowsec * SECTOR_SIZE;
118*433d6423SLionel Sambuc dv->dv_size = (u64_t)(part_limit - pe->lowsec) * SECTOR_SIZE;
119*433d6423SLionel Sambuc
120*433d6423SLionel Sambuc if (style == P_PRIMARY) {
121*433d6423SLionel Sambuc /* Each Minix primary partition can be subpartitioned. */
122*433d6423SLionel Sambuc if (pe->sysind == MINIX_PART)
123*433d6423SLionel Sambuc parse_part_table(bdp, device + par, P_SUB, atapi,
124*433d6423SLionel Sambuc tmp_buf);
125*433d6423SLionel Sambuc
126*433d6423SLionel Sambuc /* An extended partition has logical partitions. */
127*433d6423SLionel Sambuc if (ext_part(pe->sysind))
128*433d6423SLionel Sambuc extpartition(bdp, device + par, pe->lowsec, tmp_buf);
129*433d6423SLionel Sambuc }
130*433d6423SLionel Sambuc }
131*433d6423SLionel Sambuc }
132*433d6423SLionel Sambuc
133*433d6423SLionel Sambuc /*============================================================================*
134*433d6423SLionel Sambuc * extpartition *
135*433d6423SLionel Sambuc *============================================================================*/
extpartition(struct blockdriver * bdp,int extdev,unsigned long extbase,u8_t * tmp_buf)136*433d6423SLionel Sambuc static void extpartition(
137*433d6423SLionel Sambuc struct blockdriver *bdp, /* device dependent entry points */
138*433d6423SLionel Sambuc int extdev, /* extended partition to scan */
139*433d6423SLionel Sambuc unsigned long extbase, /* sector offset of the base ext. partition */
140*433d6423SLionel Sambuc u8_t *tmp_buf /* temporary buffer */
141*433d6423SLionel Sambuc )
142*433d6423SLionel Sambuc {
143*433d6423SLionel Sambuc /* Extended partitions cannot be ignored alas, because people like to move
144*433d6423SLionel Sambuc * files to and from DOS partitions. Avoid reading this code, it's no fun.
145*433d6423SLionel Sambuc */
146*433d6423SLionel Sambuc struct part_entry table[NR_PARTITIONS], *pe;
147*433d6423SLionel Sambuc int subdev, disk, par;
148*433d6423SLionel Sambuc struct device *dv;
149*433d6423SLionel Sambuc unsigned long offset, nextoffset;
150*433d6423SLionel Sambuc
151*433d6423SLionel Sambuc disk = extdev / DEV_PER_DRIVE;
152*433d6423SLionel Sambuc par = extdev % DEV_PER_DRIVE - 1;
153*433d6423SLionel Sambuc subdev = MINOR_d0p0s0 + (disk * NR_PARTITIONS + par) * NR_PARTITIONS;
154*433d6423SLionel Sambuc
155*433d6423SLionel Sambuc offset = 0;
156*433d6423SLionel Sambuc do {
157*433d6423SLionel Sambuc if (!get_part_table(bdp, extdev, offset, table, tmp_buf)) return;
158*433d6423SLionel Sambuc sort(table);
159*433d6423SLionel Sambuc
160*433d6423SLionel Sambuc /* The table should contain one logical partition and optionally
161*433d6423SLionel Sambuc * another extended partition. (It's a linked list.)
162*433d6423SLionel Sambuc */
163*433d6423SLionel Sambuc nextoffset = 0;
164*433d6423SLionel Sambuc for (par = 0; par < NR_PARTITIONS; par++) {
165*433d6423SLionel Sambuc pe = &table[par];
166*433d6423SLionel Sambuc if (ext_part(pe->sysind)) {
167*433d6423SLionel Sambuc nextoffset = pe->lowsec;
168*433d6423SLionel Sambuc } else
169*433d6423SLionel Sambuc if (pe->sysind != NO_PART) {
170*433d6423SLionel Sambuc if ((dv = (*bdp->bdr_part)(subdev)) == NULL) return;
171*433d6423SLionel Sambuc
172*433d6423SLionel Sambuc dv->dv_base = (u64_t)(extbase + offset + pe->lowsec) *
173*433d6423SLionel Sambuc SECTOR_SIZE;
174*433d6423SLionel Sambuc dv->dv_size = (u64_t)pe->size * SECTOR_SIZE;
175*433d6423SLionel Sambuc
176*433d6423SLionel Sambuc /* Out of devices? */
177*433d6423SLionel Sambuc if (++subdev % NR_PARTITIONS == 0) return;
178*433d6423SLionel Sambuc }
179*433d6423SLionel Sambuc }
180*433d6423SLionel Sambuc } while ((offset = nextoffset) != 0);
181*433d6423SLionel Sambuc }
182*433d6423SLionel Sambuc
183*433d6423SLionel Sambuc /*============================================================================*
184*433d6423SLionel Sambuc * get_part_table *
185*433d6423SLionel Sambuc *============================================================================*/
get_part_table(struct blockdriver * bdp,int device,unsigned long offset,struct part_entry * table,u8_t * tmp_buf)186*433d6423SLionel Sambuc static int get_part_table(
187*433d6423SLionel Sambuc struct blockdriver *bdp,
188*433d6423SLionel Sambuc int device,
189*433d6423SLionel Sambuc unsigned long offset, /* sector offset to the table */
190*433d6423SLionel Sambuc struct part_entry *table, /* four entries */
191*433d6423SLionel Sambuc u8_t *tmp_buf) /* temporary buffer */
192*433d6423SLionel Sambuc {
193*433d6423SLionel Sambuc /* Read the partition table for the device, return true iff there were no
194*433d6423SLionel Sambuc * errors.
195*433d6423SLionel Sambuc */
196*433d6423SLionel Sambuc iovec_t iovec1;
197*433d6423SLionel Sambuc u64_t position;
198*433d6423SLionel Sambuc int r;
199*433d6423SLionel Sambuc
200*433d6423SLionel Sambuc position = (u64_t)offset * SECTOR_SIZE;
201*433d6423SLionel Sambuc iovec1.iov_addr = (vir_bytes) tmp_buf;
202*433d6423SLionel Sambuc iovec1.iov_size = CD_SECTOR_SIZE;
203*433d6423SLionel Sambuc r = (*bdp->bdr_transfer)(device, FALSE /*do_write*/, position, SELF,
204*433d6423SLionel Sambuc &iovec1, 1, BDEV_NOFLAGS);
205*433d6423SLionel Sambuc if (r != CD_SECTOR_SIZE) {
206*433d6423SLionel Sambuc return 0;
207*433d6423SLionel Sambuc }
208*433d6423SLionel Sambuc if (tmp_buf[510] != 0x55 || tmp_buf[511] != 0xAA) {
209*433d6423SLionel Sambuc /* Invalid partition table. */
210*433d6423SLionel Sambuc return 0;
211*433d6423SLionel Sambuc }
212*433d6423SLionel Sambuc memcpy(table, (tmp_buf + PART_TABLE_OFF), NR_PARTITIONS * sizeof(table[0]));
213*433d6423SLionel Sambuc return 1;
214*433d6423SLionel Sambuc }
215*433d6423SLionel Sambuc
216*433d6423SLionel Sambuc /*===========================================================================*
217*433d6423SLionel Sambuc * sort *
218*433d6423SLionel Sambuc *===========================================================================*/
sort(struct part_entry * table)219*433d6423SLionel Sambuc static void sort(struct part_entry *table)
220*433d6423SLionel Sambuc {
221*433d6423SLionel Sambuc /* Sort a partition table. */
222*433d6423SLionel Sambuc struct part_entry *pe, tmp;
223*433d6423SLionel Sambuc int n = NR_PARTITIONS;
224*433d6423SLionel Sambuc
225*433d6423SLionel Sambuc do {
226*433d6423SLionel Sambuc for (pe = table; pe < table + NR_PARTITIONS-1; pe++) {
227*433d6423SLionel Sambuc if (pe[0].sysind == NO_PART
228*433d6423SLionel Sambuc || (pe[0].lowsec > pe[1].lowsec
229*433d6423SLionel Sambuc && pe[1].sysind != NO_PART)) {
230*433d6423SLionel Sambuc tmp = pe[0]; pe[0] = pe[1]; pe[1] = tmp;
231*433d6423SLionel Sambuc }
232*433d6423SLionel Sambuc }
233*433d6423SLionel Sambuc } while (--n > 0);
234*433d6423SLionel Sambuc }
235