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 "kernel.h"
   8: #include "driver.h"
   9: #include "drvlib.h"
  10: 
  11: /* Extended partition? */
  12: #define ext_part(s)     ((s) == 0x05 || (s) == 0x0F)
  13: 
  14: FORWARD _PROTOTYPE( void extpartition, (struct driver *dp, int extdev,
  15:                                                 unsigned long extbase) );
  16: FORWARD _PROTOTYPE( int get_part_table, (struct driver *dp, int device,
  17:                         unsigned long offset, struct part_entry *table) );
  18: FORWARD _PROTOTYPE( void sort, (struct part_entry *table) );
  19: 
  20: 
  21: /*============================================================================*
  22:  *                              partition                                     *
  23:  *============================================================================*/
  24: PUBLIC void partition(dp, device, style)
  25: struct driver *dp;      /* device dependent entry points */
  26: int device;             /* device to partition */
  27: int style;              /* partitioning style: floppy, primary, sub. */
  28: {
  29: /* This routine is called on first open to initialize the partition tables
  30:  * of a device.  It makes sure that each partition falls safely within the
  31:  * device's limits.  Depending on the partition style we are either making
  32:  * floppy partitions, primary partitions or subpartitions.  Only primary
  33:  * partitions are sorted, because they are shared with other operating
  34:  * systems that expect this.
  35:  */
  36:   struct part_entry table[NR_PARTITIONS], *pe;
  37:   int disk, par;
  38:   struct device *dv;
  39:   unsigned long base, limit, part_limit;
  40: 
  41:   /* Get the geometry of the device to partition */
  42:   if ((dv = (*dp->dr_prepare)(device)) == NIL_DEV
  43:                                 || cmp64u(dv->dv_size, 0) == 0) return;
  44:   base = div64u(dv->dv_base, SECTOR_SIZE);
  45:   limit = base + div64u(dv->dv_size, SECTOR_SIZE);
  46: 
  47:   /* Read the partition table for the device. */
  48:   if (!get_part_table(dp, device, 0L, table)) return;
  49: 
  50:   /* Compute the device number of the first partition. */
  51:   switch (style) {
  52:   case P_FLOPPY:
  53:         device += MINOR_fd0p0;
  54:         break;
  55:   case P_PRIMARY:
  56:         sort(table);            /* sort a primary partition table */
  57:         device += 1;
  58:         break;
  59:   case P_SUB:
  60:         disk = device / DEV_PER_DRIVE;
  61:         par = device % DEV_PER_DRIVE - 1;
  62:         device = MINOR_d0p0s0 + (disk * NR_PARTITIONS + par) * NR_PARTITIONS;
  63:   }
  64: 
  65:   /* Find an array of devices. */
  66:   if ((dv = (*dp->dr_prepare)(device)) == NIL_DEV) return;
  67: 
  68:   /* Set the geometry of the partitions from the partition table. */
  69:   for (par = 0; par < NR_PARTITIONS; par++, dv++) {
  70:         /* Shrink the partition to fit within the device. */
  71:         pe = &table[par];
  72:         part_limit = pe->lowsec + pe->size;
  73:         if (part_limit < pe->lowsec) part_limit = limit;
  74:         if (part_limit > limit) part_limit = limit;
  75:         if (pe->lowsec < base) pe->lowsec = base;
  76:         if (part_limit < pe->lowsec) part_limit = pe->lowsec;
  77: 
  78:         dv->dv_base = mul64u(pe->lowsec, SECTOR_SIZE);
  79:         dv->dv_size = mul64u(part_limit - pe->lowsec, SECTOR_SIZE);
  80: 
  81:         if (style == P_PRIMARY) {
  82:                 /* Each Minix primary partition can be subpartitioned. */
  83:                 if (pe->sysind == MINIX_PART)
  84:                         partition(dp, device + par, P_SUB);
  85: 
  86:                 /* An extended partition has logical partitions. */
  87:                 if (ext_part(pe->sysind))
  88:                         extpartition(dp, device + par, pe->lowsec);
  89:         }
  90:   }
  91: }
  92: 
  93: 
  94: /*============================================================================*
  95:  *                              extpartition                                  *
  96:  *============================================================================*/
  97: PRIVATE void extpartition(dp, extdev, extbase)
  98: struct driver *dp;      /* device dependent entry points */
  99: int extdev;             /* extended partition to scan */
 100: unsigned long extbase;  /* sector offset of the base extended partition */
 101: {
 102: /* Extended partitions cannot be ignored alas, because people like to move
 103:  * files to and from DOS partitions.  Avoid reading this code, it's no fun.
 104:  */
 105:   struct part_entry table[NR_PARTITIONS], *pe;
 106:   int subdev, disk, par;
 107:   struct device *dv;
 108:   unsigned long offset, nextoffset;
 109: 
 110:   disk = extdev / DEV_PER_DRIVE;
 111:   par = extdev % DEV_PER_DRIVE - 1;
 112:   subdev = MINOR_d0p0s0 + (disk * NR_PARTITIONS + par) * NR_PARTITIONS;
 113: 
 114:   offset = 0;
 115:   do {
 116:         if (!get_part_table(dp, extdev, offset, table)) return;
 117:         sort(table);
 118: 
 119:         /* The table should contain one logical partition and optionally
 120:          * another extended partition.  (It's a linked list.)
 121:          */
 122:         nextoffset = 0;
 123:         for (par = 0; par < NR_PARTITIONS; par++) {
 124:                 pe = &table[par];
 125:                 if (ext_part(pe->sysind)) {
 126:                         nextoffset = pe->lowsec;
 127:                 } else
 128:                 if (pe->sysind != NO_PART) {
 129:                         if ((dv = (*dp->dr_prepare)(subdev)) == NIL_DEV) return;
 130: 
 131:                         dv->dv_base = mul64u(extbase + offset + pe->lowsec,
 132:                                                                 SECTOR_SIZE);
 133:                         dv->dv_size = mul64u(pe->size, SECTOR_SIZE);
 134: 
 135:                         /* Out of devices? */
 136:                         if (++subdev % NR_PARTITIONS == 0) return;
 137:                 }
 138:         }
 139:   } while ((offset = nextoffset) != 0);
 140: }
 141: 
 142: 
 143: /*============================================================================*
 144:  *                              get_part_table                                *
 145:  *============================================================================*/
 146: PRIVATE int get_part_table(dp, device, offset, table)
 147: struct driver *dp;
 148: int device;
 149: unsigned long offset;           /* sector offset to the table */
 150: struct part_entry *table;       /* four entries */
 151: {
 152: /* Read the partition table for the device, return true iff there were no
 153:  * errors.
 154:  */
 155:   iovec_t iovec1;
 156:   off_t position;
 157:   int proc_nr;
 158: 
 159:   /* Read the partition table at 'offset'. */
 160:   proc_nr = proc_number(proc_ptr);
 161:   position = offset << SECTOR_SHIFT;
 162:   iovec1.iov_addr = (vir_bytes) tmp_buf;
 163:   iovec1.iov_size = SECTOR_SIZE;
 164:   if ((*dp->dr_prepare)(device) != NIL_DEV) {
 165:         (void) (*dp->dr_transfer)(proc_nr, DEV_GATHER, position, &iovec1, 1);
 166:   }
 167:   if (iovec1.iov_size != 0) {
 168:         printf("%s: can't read partition table\n", (*dp->dr_name)());
 169:         return 0;
 170:   }
 171:   if (tmp_buf[510] != 0x55 || tmp_buf[511] != 0xAA) {
 172:         /* Invalid partition table. */
 173:         return 0;
 174:   }
 175:   memcpy(table, (tmp_buf + PART_TABLE_OFF), NR_PARTITIONS * sizeof(table[0]));
 176:   return 1;
 177: }
 178: 
 179: 
 180: /*===========================================================================*
 181:  *                              sort                                         *
 182:  *===========================================================================*/
 183: PRIVATE void sort(table)
 184: struct part_entry *table;
 185: {
 186: /* Sort a partition table. */
 187:   struct part_entry *pe, tmp;
 188:   int n = NR_PARTITIONS;
 189: 
 190:   do {
 191:         for (pe = table; pe < table + NR_PARTITIONS-1; pe++) {
 192:                 if (pe[0].sysind == NO_PART
 193:                         || (pe[0].lowsec > pe[1].lowsec
 194:                                         && pe[1].sysind != NO_PART)) {
 195:                         tmp = pe[0]; pe[0] = pe[1]; pe[1] = tmp;
 196:                 }
 197:         }
 198:   } while (--n > 0);
 199: }