17dd7cddfSDavid du Colombier #include <u.h> 27dd7cddfSDavid du Colombier #include <libc.h> 37dd7cddfSDavid du Colombier #include <bio.h> 47dd7cddfSDavid du Colombier #include <ctype.h> 57dd7cddfSDavid du Colombier #include <disk.h> 67dd7cddfSDavid du Colombier 77dd7cddfSDavid du Colombier static Disk* 87dd7cddfSDavid du Colombier mkwidth(Disk *disk) 97dd7cddfSDavid du Colombier { 107dd7cddfSDavid du Colombier char buf[40]; 117dd7cddfSDavid du Colombier 127dd7cddfSDavid du Colombier sprint(buf, "%lld", disk->size); 137dd7cddfSDavid du Colombier disk->width = strlen(buf); 147dd7cddfSDavid du Colombier return disk; 157dd7cddfSDavid du Colombier } 167dd7cddfSDavid du Colombier 177dd7cddfSDavid du Colombier /* 187dd7cddfSDavid du Colombier * Discover the disk geometry by various sleazeful means. 197dd7cddfSDavid du Colombier * 207dd7cddfSDavid du Colombier * First, if there is a partition table in sector 0, 217dd7cddfSDavid du Colombier * see if all the partitions have the same end head 227dd7cddfSDavid du Colombier * and sector; if so, we'll assume that that's the 237dd7cddfSDavid du Colombier * right count. 247dd7cddfSDavid du Colombier * 257dd7cddfSDavid du Colombier * If that fails, we'll try looking at the geometry that the ATA 267dd7cddfSDavid du Colombier * driver supplied, if any, and translate that as a 277dd7cddfSDavid du Colombier * BIOS might. 287dd7cddfSDavid du Colombier * 297dd7cddfSDavid du Colombier * If that too fails, which should only happen on a SCSI 307dd7cddfSDavid du Colombier * disk with no currently defined partitions, we'll try 317dd7cddfSDavid du Colombier * various common (h, s) pairs used by BIOSes when faking 327dd7cddfSDavid du Colombier * the geometries. 337dd7cddfSDavid du Colombier */ 347dd7cddfSDavid du Colombier typedef struct Table Table; 357dd7cddfSDavid du Colombier typedef struct Tentry Tentry; 367dd7cddfSDavid du Colombier struct Tentry { 377dd7cddfSDavid du Colombier uchar active; /* active flag */ 387dd7cddfSDavid du Colombier uchar starth; /* starting head */ 397dd7cddfSDavid du Colombier uchar starts; /* starting sector */ 407dd7cddfSDavid du Colombier uchar startc; /* starting cylinder */ 417dd7cddfSDavid du Colombier uchar type; /* partition type */ 427dd7cddfSDavid du Colombier uchar endh; /* ending head */ 437dd7cddfSDavid du Colombier uchar ends; /* ending sector */ 447dd7cddfSDavid du Colombier uchar endc; /* ending cylinder */ 457dd7cddfSDavid du Colombier uchar xlba[4]; /* starting LBA from beginning of disc */ 467dd7cddfSDavid du Colombier uchar xsize[4]; /* size in sectors */ 477dd7cddfSDavid du Colombier }; 487dd7cddfSDavid du Colombier enum { 497dd7cddfSDavid du Colombier Toffset = 446, /* offset of partition table in sector */ 507dd7cddfSDavid du Colombier Magic0 = 0x55, 517dd7cddfSDavid du Colombier Magic1 = 0xAA, 527dd7cddfSDavid du Colombier NTentry = 4, 537dd7cddfSDavid du Colombier }; 547dd7cddfSDavid du Colombier struct Table { 557dd7cddfSDavid du Colombier Tentry entry[NTentry]; 567dd7cddfSDavid du Colombier uchar magic[2]; 577dd7cddfSDavid du Colombier }; 587dd7cddfSDavid du Colombier static int 597dd7cddfSDavid du Colombier partitiongeometry(Disk *disk) 607dd7cddfSDavid du Colombier { 613ff48bf5SDavid du Colombier char *rawname; 623ff48bf5SDavid du Colombier int i, h, rawfd, s; 637dd7cddfSDavid du Colombier uchar buf[512]; 647dd7cddfSDavid du Colombier Table *t; 657dd7cddfSDavid du Colombier 667dd7cddfSDavid du Colombier t = (Table*)(buf + Toffset); 673ff48bf5SDavid du Colombier 683ff48bf5SDavid du Colombier /* 693ff48bf5SDavid du Colombier * look for an MBR first in the /dev/sdXX/data partition, otherwise 703ff48bf5SDavid du Colombier * attempt to fall back on the current partition. 713ff48bf5SDavid du Colombier */ 723ff48bf5SDavid du Colombier rawname = malloc(strlen(disk->prefix) + 5); /* prefix + "data" + nul */ 733ff48bf5SDavid du Colombier if(rawname == nil) 747dd7cddfSDavid du Colombier return -1; 757dd7cddfSDavid du Colombier 763ff48bf5SDavid du Colombier strcpy(rawname, disk->prefix); 773ff48bf5SDavid du Colombier strcat(rawname, "data"); 783ff48bf5SDavid du Colombier rawfd = open(rawname, OREAD); 793ff48bf5SDavid du Colombier free(rawname); 803ff48bf5SDavid du Colombier if(rawfd >= 0 813ff48bf5SDavid du Colombier && seek(rawfd, 0, 0) >= 0 823ff48bf5SDavid du Colombier && readn(rawfd, buf, 512) == 512 833ff48bf5SDavid du Colombier && t->magic[0] == Magic0 843ff48bf5SDavid du Colombier && t->magic[1] == Magic1) { 853ff48bf5SDavid du Colombier close(rawfd); 863ff48bf5SDavid du Colombier } else { 873ff48bf5SDavid du Colombier if(rawfd >= 0) 883ff48bf5SDavid du Colombier close(rawfd); 893ff48bf5SDavid du Colombier if(seek(disk->fd, 0, 0) < 0 903ff48bf5SDavid du Colombier || readn(disk->fd, buf, 512) != 512 913ff48bf5SDavid du Colombier || t->magic[0] != Magic0 923ff48bf5SDavid du Colombier || t->magic[1] != Magic1) { 933ff48bf5SDavid du Colombier return -1; 943ff48bf5SDavid du Colombier } 953ff48bf5SDavid du Colombier } 963ff48bf5SDavid du Colombier 977dd7cddfSDavid du Colombier h = s = -1; 987dd7cddfSDavid du Colombier for(i=0; i<NTentry; i++) { 997dd7cddfSDavid du Colombier if(t->entry[i].type == 0) 1007dd7cddfSDavid du Colombier continue; 1017dd7cddfSDavid du Colombier 1027dd7cddfSDavid du Colombier t->entry[i].ends &= 63; 1037dd7cddfSDavid du Colombier if(h == -1) { 1047dd7cddfSDavid du Colombier h = t->entry[i].endh; 1057dd7cddfSDavid du Colombier s = t->entry[i].ends; 1067dd7cddfSDavid du Colombier } else { 1077dd7cddfSDavid du Colombier /* 1087dd7cddfSDavid du Colombier * Only accept the partition info if every 1097dd7cddfSDavid du Colombier * partition is consistent. 1107dd7cddfSDavid du Colombier */ 1117dd7cddfSDavid du Colombier if(h != t->entry[i].endh || s != t->entry[i].ends) 1127dd7cddfSDavid du Colombier return -1; 1137dd7cddfSDavid du Colombier } 1147dd7cddfSDavid du Colombier } 1157dd7cddfSDavid du Colombier 1167dd7cddfSDavid du Colombier if(h == -1) 1177dd7cddfSDavid du Colombier return -1; 1187dd7cddfSDavid du Colombier 1197dd7cddfSDavid du Colombier disk->h = h+1; /* heads count from 0 */ 1207dd7cddfSDavid du Colombier disk->s = s; /* sectors count from 1 */ 1217dd7cddfSDavid du Colombier disk->c = disk->secs / (disk->h*disk->s); 1227dd7cddfSDavid du Colombier disk->chssrc = Gpart; 1237dd7cddfSDavid du Colombier return 0; 1247dd7cddfSDavid du Colombier } 1257dd7cddfSDavid du Colombier 1267dd7cddfSDavid du Colombier /* 1277dd7cddfSDavid du Colombier * If there is ATA geometry, use it, perhaps massaged. 1287dd7cddfSDavid du Colombier */ 1297dd7cddfSDavid du Colombier static int 1307dd7cddfSDavid du Colombier drivergeometry(Disk *disk) 1317dd7cddfSDavid du Colombier { 1327dd7cddfSDavid du Colombier int m; 1337dd7cddfSDavid du Colombier 1347dd7cddfSDavid du Colombier if(disk->c == 0 || disk->h == 0 || disk->s == 0) 1357dd7cddfSDavid du Colombier return -1; 1367dd7cddfSDavid du Colombier 1377dd7cddfSDavid du Colombier disk->chssrc = Gdisk; 1387dd7cddfSDavid du Colombier if(disk->c < 1024) 1397dd7cddfSDavid du Colombier return 0; 1407dd7cddfSDavid du Colombier 1417dd7cddfSDavid du Colombier switch(disk->h) { 1427dd7cddfSDavid du Colombier case 15: 1437dd7cddfSDavid du Colombier disk->h = 255; 1447dd7cddfSDavid du Colombier disk->c /= 17; 1457dd7cddfSDavid du Colombier return 0; 1467dd7cddfSDavid du Colombier 1477dd7cddfSDavid du Colombier default: 1487dd7cddfSDavid du Colombier for(m = 2; m*disk->h < 256; m *= 2) { 1497dd7cddfSDavid du Colombier if(disk->c/m < 1024) { 1507dd7cddfSDavid du Colombier disk->c /= m; 1517dd7cddfSDavid du Colombier disk->h *= m; 1527dd7cddfSDavid du Colombier return 0; 1537dd7cddfSDavid du Colombier } 1547dd7cddfSDavid du Colombier } 1557dd7cddfSDavid du Colombier 1567dd7cddfSDavid du Colombier /* set to 255, 63 and be done with it */ 1577dd7cddfSDavid du Colombier disk->h = 255; 1587dd7cddfSDavid du Colombier disk->s = 63; 1597dd7cddfSDavid du Colombier disk->c = disk->secs / (disk->h * disk->s); 1607dd7cddfSDavid du Colombier return 0; 1617dd7cddfSDavid du Colombier } 1627dd7cddfSDavid du Colombier return -1; /* not reached */ 1637dd7cddfSDavid du Colombier } 1647dd7cddfSDavid du Colombier 1657dd7cddfSDavid du Colombier /* 1667dd7cddfSDavid du Colombier * There's no ATA geometry and no partitions. 1677dd7cddfSDavid du Colombier * Our guess is as good as anyone's. 1687dd7cddfSDavid du Colombier */ 1697dd7cddfSDavid du Colombier static struct { 1707dd7cddfSDavid du Colombier int h; 1717dd7cddfSDavid du Colombier int s; 1727dd7cddfSDavid du Colombier } guess[] = { 1737dd7cddfSDavid du Colombier 64, 32, 1747dd7cddfSDavid du Colombier 64, 63, 1757dd7cddfSDavid du Colombier 128, 63, 1767dd7cddfSDavid du Colombier 255, 63, 1777dd7cddfSDavid du Colombier }; 1787dd7cddfSDavid du Colombier static int 1797dd7cddfSDavid du Colombier guessgeometry(Disk *disk) 1807dd7cddfSDavid du Colombier { 1817dd7cddfSDavid du Colombier int i; 1827dd7cddfSDavid du Colombier long c; 1837dd7cddfSDavid du Colombier 1847dd7cddfSDavid du Colombier disk->chssrc = Gguess; 1857dd7cddfSDavid du Colombier c = 1024; 1867dd7cddfSDavid du Colombier for(i=0; i<nelem(guess); i++) 1877dd7cddfSDavid du Colombier if(c*guess[i].h*guess[i].s >= disk->secs) { 1887dd7cddfSDavid du Colombier disk->h = guess[i].h; 1897dd7cddfSDavid du Colombier disk->s = guess[i].s; 1907dd7cddfSDavid du Colombier disk->c = disk->secs / (disk->h * disk->s); 1917dd7cddfSDavid du Colombier return 0; 1927dd7cddfSDavid du Colombier } 1937dd7cddfSDavid du Colombier 1947dd7cddfSDavid du Colombier /* use maximum values */ 1957dd7cddfSDavid du Colombier disk->h = 255; 1967dd7cddfSDavid du Colombier disk->s = 63; 1977dd7cddfSDavid du Colombier disk->c = disk->secs / (disk->h * disk->s); 1987dd7cddfSDavid du Colombier return 0; 1997dd7cddfSDavid du Colombier } 2007dd7cddfSDavid du Colombier 2017dd7cddfSDavid du Colombier static void 2027dd7cddfSDavid du Colombier findgeometry(Disk *disk) 2037dd7cddfSDavid du Colombier { 2047dd7cddfSDavid du Colombier if(partitiongeometry(disk) < 0 2057dd7cddfSDavid du Colombier && drivergeometry(disk) < 0 2067dd7cddfSDavid du Colombier && guessgeometry(disk) < 0) { /* can't happen */ 2077dd7cddfSDavid du Colombier print("we're completely confused about your disk; sorry\n"); 2087dd7cddfSDavid du Colombier assert(0); 2097dd7cddfSDavid du Colombier } 2107dd7cddfSDavid du Colombier } 2117dd7cddfSDavid du Colombier 2127dd7cddfSDavid du Colombier static Disk* 2137dd7cddfSDavid du Colombier openfile(Disk *disk) 2147dd7cddfSDavid du Colombier { 2159a747e4fSDavid du Colombier Dir *d; 2167dd7cddfSDavid du Colombier 2179a747e4fSDavid du Colombier if((d = dirfstat(disk->fd)) == nil){ 2187dd7cddfSDavid du Colombier free(disk); 2197dd7cddfSDavid du Colombier return nil; 2207dd7cddfSDavid du Colombier } 2217dd7cddfSDavid du Colombier 2227dd7cddfSDavid du Colombier disk->secsize = 512; 2239a747e4fSDavid du Colombier disk->size = d->length; 2247dd7cddfSDavid du Colombier disk->secs = disk->size / disk->secsize; 2257dd7cddfSDavid du Colombier disk->offset = 0; 2269a747e4fSDavid du Colombier free(d); 2277dd7cddfSDavid du Colombier 2287dd7cddfSDavid du Colombier findgeometry(disk); 2297dd7cddfSDavid du Colombier return mkwidth(disk); 2307dd7cddfSDavid du Colombier } 2317dd7cddfSDavid du Colombier 2327dd7cddfSDavid du Colombier static Disk* 2337dd7cddfSDavid du Colombier opensd(Disk *disk) 2347dd7cddfSDavid du Colombier { 2357dd7cddfSDavid du Colombier Biobuf b; 2367dd7cddfSDavid du Colombier char *p, *f[10]; 2377dd7cddfSDavid du Colombier int nf; 2387dd7cddfSDavid du Colombier 2397dd7cddfSDavid du Colombier Binit(&b, disk->ctlfd, OREAD); 2407dd7cddfSDavid du Colombier while(p = Brdline(&b, '\n')) { 2417dd7cddfSDavid du Colombier p[Blinelen(&b)-1] = '\0'; 2427dd7cddfSDavid du Colombier nf = tokenize(p, f, nelem(f)); 2437dd7cddfSDavid du Colombier if(nf >= 3 && strcmp(f[0], "geometry") == 0) { 2447dd7cddfSDavid du Colombier disk->secsize = strtoll(f[2], 0, 0); 2457dd7cddfSDavid du Colombier if(nf >= 6) { 2467dd7cddfSDavid du Colombier disk->c = strtol(f[3], 0, 0); 2477dd7cddfSDavid du Colombier disk->h = strtol(f[4], 0, 0); 2487dd7cddfSDavid du Colombier disk->s = strtol(f[5], 0, 0); 2497dd7cddfSDavid du Colombier } 2507dd7cddfSDavid du Colombier } 2517dd7cddfSDavid du Colombier if(nf >= 4 && strcmp(f[0], "part") == 0 && strcmp(f[1], disk->part) == 0) { 2527dd7cddfSDavid du Colombier disk->offset = strtoll(f[2], 0, 0); 2537dd7cddfSDavid du Colombier disk->secs = strtoll(f[3], 0, 0) - disk->offset; 2547dd7cddfSDavid du Colombier } 2557dd7cddfSDavid du Colombier } 2567dd7cddfSDavid du Colombier 2577dd7cddfSDavid du Colombier 2587dd7cddfSDavid du Colombier disk->size = disk->secs * disk->secsize; 2597dd7cddfSDavid du Colombier if(disk->size <= 0) { 2607dd7cddfSDavid du Colombier strcpy(disk->part, ""); 2617dd7cddfSDavid du Colombier disk->type = Tfile; 2627dd7cddfSDavid du Colombier return openfile(disk); 2637dd7cddfSDavid du Colombier } 2647dd7cddfSDavid du Colombier 2657dd7cddfSDavid du Colombier findgeometry(disk); 2667dd7cddfSDavid du Colombier return mkwidth(disk); 2677dd7cddfSDavid du Colombier } 2687dd7cddfSDavid du Colombier 2697dd7cddfSDavid du Colombier Disk* 2707dd7cddfSDavid du Colombier opendisk(char *disk, int rdonly, int noctl) 2717dd7cddfSDavid du Colombier { 2727dd7cddfSDavid du Colombier char *p, *q; 2737dd7cddfSDavid du Colombier Disk *d; 2747dd7cddfSDavid du Colombier 275*766ccd67SDavid du Colombier d = mallocz(sizeof(*d), 1); 27659cc4ca5SDavid du Colombier if(d == nil) 27759cc4ca5SDavid du Colombier return nil; 27859cc4ca5SDavid du Colombier 2797dd7cddfSDavid du Colombier d->fd = d->wfd = d->ctlfd = -1; 2807dd7cddfSDavid du Colombier d->rdonly = rdonly; 2817dd7cddfSDavid du Colombier 2827dd7cddfSDavid du Colombier d->fd = open(disk, OREAD); 2837dd7cddfSDavid du Colombier if(d->fd < 0) { 2847dd7cddfSDavid du Colombier werrstr("cannot open disk file"); 2857dd7cddfSDavid du Colombier free(d); 2867dd7cddfSDavid du Colombier return nil; 2877dd7cddfSDavid du Colombier } 2887dd7cddfSDavid du Colombier 2897dd7cddfSDavid du Colombier if(rdonly == 0) { 2907dd7cddfSDavid du Colombier d->wfd = open(disk, OWRITE); 2917dd7cddfSDavid du Colombier if(d->wfd < 0) 2927dd7cddfSDavid du Colombier d->rdonly = 1; 2937dd7cddfSDavid du Colombier } 2947dd7cddfSDavid du Colombier 2957dd7cddfSDavid du Colombier if(noctl) 2967dd7cddfSDavid du Colombier return openfile(d); 2977dd7cddfSDavid du Colombier 2983ff48bf5SDavid du Colombier p = malloc(strlen(disk) + 4); /* 4: slop for "ctl\0" */ 29959cc4ca5SDavid du Colombier if(p == nil) { 30059cc4ca5SDavid du Colombier close(d->wfd); 30159cc4ca5SDavid du Colombier close(d->fd); 30259cc4ca5SDavid du Colombier free(d); 30359cc4ca5SDavid du Colombier return nil; 30459cc4ca5SDavid du Colombier } 3053ff48bf5SDavid du Colombier strcpy(p, disk); 3067dd7cddfSDavid du Colombier 3077dd7cddfSDavid du Colombier /* check for floppy(3) disk */ 3087dd7cddfSDavid du Colombier if(strlen(p) >= 7) { 3097dd7cddfSDavid du Colombier q = p+strlen(p)-7; 3107dd7cddfSDavid du Colombier if(q[0] == 'f' && q[1] == 'd' && isdigit(q[2]) && strcmp(q+3, "disk") == 0) { 3117dd7cddfSDavid du Colombier strcpy(q+3, "ctl"); 3127dd7cddfSDavid du Colombier if((d->ctlfd = open(p, ORDWR)) >= 0) { 3137dd7cddfSDavid du Colombier *q = '\0'; 3147dd7cddfSDavid du Colombier d->prefix = p; 3157dd7cddfSDavid du Colombier d->type = Tfloppy; 3167dd7cddfSDavid du Colombier return openfile(d); 3177dd7cddfSDavid du Colombier } 3187dd7cddfSDavid du Colombier } 3197dd7cddfSDavid du Colombier } 3207dd7cddfSDavid du Colombier 3217dd7cddfSDavid du Colombier /* attempt to find sd(3) disk or partition */ 3227dd7cddfSDavid du Colombier if(q = strrchr(p, '/')) 3237dd7cddfSDavid du Colombier q++; 3247dd7cddfSDavid du Colombier else 3257dd7cddfSDavid du Colombier q = p; 3267dd7cddfSDavid du Colombier 3277dd7cddfSDavid du Colombier strcpy(q, "ctl"); 3287dd7cddfSDavid du Colombier if((d->ctlfd = open(p, ORDWR)) >= 0) { 3297dd7cddfSDavid du Colombier *q = '\0'; 3307dd7cddfSDavid du Colombier d->prefix = p; 3317dd7cddfSDavid du Colombier d->type = Tsd; 3329a747e4fSDavid du Colombier d->part = strdup(disk+(q-p)); 3339a747e4fSDavid du Colombier if(d->part == nil){ 3349a747e4fSDavid du Colombier close(d->ctlfd); 3359a747e4fSDavid du Colombier close(d->wfd); 3369a747e4fSDavid du Colombier close(d->fd); 3379a747e4fSDavid du Colombier free(p); 3389a747e4fSDavid du Colombier free(d); 3399a747e4fSDavid du Colombier return nil; 3409a747e4fSDavid du Colombier } 3417dd7cddfSDavid du Colombier return opensd(d); 3427dd7cddfSDavid du Colombier } 3437dd7cddfSDavid du Colombier 3443ff48bf5SDavid du Colombier *q = '\0'; 3453ff48bf5SDavid du Colombier d->prefix = p; 3467dd7cddfSDavid du Colombier /* assume we just have a normal file */ 3477dd7cddfSDavid du Colombier d->type = Tfile; 3487dd7cddfSDavid du Colombier return openfile(d); 3497dd7cddfSDavid du Colombier } 350