xref: /minix3/minix/lib/libblockdriver/drvlib.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
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