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