4 * I think this is mostly, or entirely, due to
5 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
7 * Merged with fdisk for other architectures, aeb, June 1998.
9 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
10 * Internationalization
12 * Licensed under GPLv2, see file LICENSE in this source tree.
15 #if ENABLE_FEATURE_SUN_LABEL
18 #define SUN_WHOLE_DISK 5
20 #define SUN_LABEL_MAGIC 0xDABE
21 #define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
22 #define SUN_SSWAP16(x) (sun_other_endian ? fdisk_swap16(x) : (uint16_t)(x))
23 #define SUN_SSWAP32(x) (sun_other_endian ? fdisk_swap32(x) : (uint32_t)(x))
25 /* Copied from linux/major.h */
26 #define FLOPPY_MAJOR 2
28 #define SCSI_IOCTL_GET_IDLUN 0x5382
30 static smallint sun_other_endian;
31 static smallint scsi_disk;
32 static smallint floppy;
42 guess_device_type(void)
46 if (fstat(dev_fd, &bootstat) < 0) {
49 } else if (S_ISBLK(bootstat.st_mode)
50 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
51 major(bootstat.st_rdev) == IDE1_MAJOR)) {
54 } else if (S_ISBLK(bootstat.st_mode)
55 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
64 static const char *const sun_sys_types[] = {
65 "\x00" "Empty" , /* 0 */
66 "\x01" "Boot" , /* 1 */
67 "\x02" "SunOS root" , /* 2 */
68 "\x03" "SunOS swap" , /* SUNOS_SWAP */
69 "\x04" "SunOS usr" , /* 4 */
70 "\x05" "Whole disk" , /* SUN_WHOLE_DISK */
71 "\x06" "SunOS stand" , /* 6 */
72 "\x07" "SunOS var" , /* 7 */
73 "\x08" "SunOS home" , /* 8 */
74 "\x82" "Linux swap" , /* LINUX_SWAP */
75 "\x83" "Linux native", /* LINUX_NATIVE */
76 "\x8e" "Linux LVM" , /* 0x8e */
77 /* New (2.2.x) raid partition with autodetect using persistent superblock */
78 "\xfd" "Linux raid autodetect", /* 0xfd */
84 set_sun_partition(int i, unsigned start, unsigned stop, int sysid)
86 sunlabel->infos[i].id = sysid;
87 sunlabel->partitions[i].start_cylinder =
88 SUN_SSWAP32(start / (g_heads * g_sectors));
89 sunlabel->partitions[i].num_sectors =
90 SUN_SSWAP32(stop - start);
100 if (sunlabel->magic != SUN_LABEL_MAGIC
101 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED
103 current_label_type = LABEL_DOS;
104 sun_other_endian = 0;
107 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
108 ush = ((unsigned short *) (sunlabel + 1)) - 1;
109 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
111 printf("Detected sun disklabel with wrong checksum.\n"
112 "Probably you'll have to set all the values,\n"
113 "e.g. heads, sectors, cylinders and partitions\n"
114 "or force a fresh label (s command in main menu)\n");
116 g_heads = SUN_SSWAP16(sunlabel->ntrks);
117 g_cylinders = SUN_SSWAP16(sunlabel->ncyl);
118 g_sectors = SUN_SSWAP16(sunlabel->nsect);
121 current_label_type = LABEL_SUN;
126 static const struct sun_predefined_drives {
129 unsigned short sparecyl;
131 unsigned short nacyl;
132 unsigned short pcylcount;
133 unsigned short ntrks;
134 unsigned short nsect;
135 unsigned short rspeed;
137 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
138 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
139 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
140 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
141 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
142 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
143 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
144 { "","SUN0104",1,974,2,1019,6,35,3662},
145 { "","SUN0207",4,1254,2,1272,9,36,3600},
146 { "","SUN0327",3,1545,2,1549,9,46,3600},
147 { "","SUN0340",0,1538,2,1544,6,72,4200},
148 { "","SUN0424",2,1151,2,2500,9,80,4400},
149 { "","SUN0535",0,1866,2,2500,7,80,5400},
150 { "","SUN0669",5,1614,2,1632,15,54,3600},
151 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
152 { "","SUN1.05",0,2036,2,2038,14,72,5400},
153 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
154 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
155 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
158 static const struct sun_predefined_drives *
159 sun_autoconfigure_scsi(void)
161 const struct sun_predefined_drives *p = NULL;
163 #ifdef SCSI_IOCTL_GET_IDLUN
173 if (ioctl(dev_fd, SCSI_IOCTL_GET_IDLUN, &id))
177 "Host: scsi%u Channel: %02u Id: %02u Lun: %02u\n",
178 /* This is very wrong (works only if you have one HBA),
179 but I haven't found a way how to get hostno
180 from the current kernel */
186 pfd = fopen_for_read("/proc/scsi/scsi");
190 while (fgets(buffer2, 2048, pfd)) {
191 if (strcmp(buffer, buffer2))
193 if (!fgets(buffer2, 2048, pfd))
195 q = strstr(buffer2, "Vendor: ");
201 *q++ = '\0'; /* truncate vendor name */
202 q = strstr(q, "Model: ");
208 q = strstr(q, " Rev: ");
212 for (i = 0; i < ARRAY_SIZE(sun_drives); i++) {
213 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
215 if (!strstr(model, sun_drives[i].model))
217 printf("Autoconfigure found a %s%s%s\n",
218 sun_drives[i].vendor,
219 (*sun_drives[i].vendor) ? " " : "",
220 sun_drives[i].model);
232 create_sunlabel(void)
234 struct hd_geometry geometry;
237 const struct sun_predefined_drives *p = NULL;
239 printf(msg_building_new_label, "sun disklabel");
241 sun_other_endian = BB_LITTLE_ENDIAN;
242 memset(MBRbuffer, 0, sizeof(MBRbuffer));
243 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
247 " ? auto configure\n"
248 " 0 custom (with hardware detected defaults)");
249 for (i = 0; i < ARRAY_SIZE(sun_drives); i++) {
250 printf(" %c %s%s%s\n",
251 i + 'a', sun_drives[i].vendor,
252 (*sun_drives[i].vendor) ? " " : "",
253 sun_drives[i].model);
256 c = read_nonempty("Select type (? for auto, 0 for custom): ");
260 if (c >= 'a' && c < 'a' + ARRAY_SIZE(sun_drives)) {
261 p = sun_drives + c - 'a';
264 if (c >= 'A' && c < 'A' + ARRAY_SIZE(sun_drives)) {
265 p = sun_drives + c - 'A';
268 if (c == '?' && scsi_disk) {
269 p = sun_autoconfigure_scsi();
272 printf("Autoconfigure failed\n");
277 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
278 g_heads = geometry.heads;
279 g_sectors = geometry.sectors;
280 g_cylinders = geometry.cylinders;
288 sunlabel->pcylcount = SUN_SSWAP16(g_cylinders);
289 sunlabel->rspeed = SUN_SSWAP16(300);
290 sunlabel->ilfact = SUN_SSWAP16(1);
291 sunlabel->sparecyl = 0;
293 g_heads = read_int(1, g_heads, 1024, 0, "Heads");
294 g_sectors = read_int(1, g_sectors, 1024, 0, "Sectors/track");
296 g_cylinders = read_int(1, g_cylinders - 2, 65535, 0, "Cylinders");
298 g_cylinders = read_int(1, 0, 65535, 0, "Cylinders");
299 sunlabel->nacyl = SUN_SSWAP16(read_int(0, 2, 65535, 0, "Alternate cylinders"));
300 sunlabel->pcylcount = SUN_SSWAP16(read_int(0, g_cylinders + SUN_SSWAP16(sunlabel->nacyl), 65535, 0, "Physical cylinders"));
301 sunlabel->rspeed = SUN_SSWAP16(read_int(1, 5400, 100000, 0, "Rotation speed (rpm)"));
302 sunlabel->ilfact = SUN_SSWAP16(read_int(1, 1, 32, 0, "Interleave factor"));
303 sunlabel->sparecyl = SUN_SSWAP16(read_int(0, 0, g_sectors, 0, "Extra sectors per cylinder"));
306 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
307 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
308 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
309 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
310 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
311 sunlabel->nsect = SUN_SSWAP16(p->nsect);
312 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
313 sunlabel->ilfact = SUN_SSWAP16(1);
314 g_cylinders = p->ncyl;
316 g_sectors = p->nsect;
317 puts("You may change all the disk params from the x menu");
320 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
321 "%s%s%s cyl %u alt %u hd %u sec %u",
322 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
323 p ? p->model : (floppy ? "3,5\" floppy" : "Linux custom"),
324 g_cylinders, SUN_SSWAP16(sunlabel->nacyl), g_heads, g_sectors);
326 sunlabel->ntrks = SUN_SSWAP16(g_heads);
327 sunlabel->nsect = SUN_SSWAP16(g_sectors);
328 sunlabel->ncyl = SUN_SSWAP16(g_cylinders);
330 set_sun_partition(0, 0, g_cylinders * g_heads * g_sectors, LINUX_NATIVE);
332 if (g_cylinders * g_heads * g_sectors >= 150 * 2048) {
333 ndiv = g_cylinders - (50 * 2048 / (g_heads * g_sectors)); /* 50M swap */
335 ndiv = g_cylinders * 2 / 3;
336 set_sun_partition(0, 0, ndiv * g_heads * g_sectors, LINUX_NATIVE);
337 set_sun_partition(1, ndiv * g_heads * g_sectors, g_cylinders * g_heads * g_sectors, LINUX_SWAP);
338 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
340 set_sun_partition(2, 0, g_cylinders * g_heads * g_sectors, SUN_WHOLE_DISK);
342 unsigned short *ush = (unsigned short *)sunlabel;
343 unsigned short csum = 0;
344 while (ush < (unsigned short *)(&sunlabel->csum))
346 sunlabel->csum = csum;
352 get_boot(CREATE_EMPTY_SUN);
356 toggle_sunflags(int i, unsigned char mask)
358 if (sunlabel->infos[i].flags & mask)
359 sunlabel->infos[i].flags &= ~mask;
361 sunlabel->infos[i].flags |= mask;
366 fetch_sun(unsigned *starts, unsigned *lens, unsigned *start, unsigned *stop)
368 int i, continuous = 1;
371 *stop = g_cylinders * g_heads * g_sectors;
372 for (i = 0; i < g_partitions; i++) {
373 if (sunlabel->partitions[i].num_sectors
374 && sunlabel->infos[i].id
375 && sunlabel->infos[i].id != SUN_WHOLE_DISK) {
376 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
377 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
379 if (starts[i] == *start)
381 else if (starts[i] + lens[i] >= *stop)
385 /* There will be probably more gaps
386 than one, so lets check afterwards */
395 static unsigned *verify_sun_starts;
398 verify_sun_cmp(int *a, int *b)
400 if (*a == -1) return 1;
401 if (*b == -1) return -1;
402 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
409 unsigned starts[8], lens[8], start, stop;
410 int i,j,k,starto,endo;
413 verify_sun_starts = starts;
414 fetch_sun(starts, lens, &start, &stop);
415 for (k = 0; k < 7; k++) {
416 for (i = 0; i < 8; i++) {
417 if (k && (lens[i] % (g_heads * g_sectors))) {
418 printf("Partition %u doesn't end on cylinder boundary\n", i+1);
421 for (j = 0; j < i; j++)
423 if (starts[j] == starts[i]+lens[i]) {
424 starts[j] = starts[i]; lens[j] += lens[i];
426 } else if (starts[i] == starts[j]+lens[j]){
430 if (starts[i] < starts[j]+lens[j]
431 && starts[j] < starts[i]+lens[i]) {
433 if (starts[j] > starto)
435 endo = starts[i]+lens[i];
436 if (starts[j]+lens[j] < endo)
437 endo = starts[j]+lens[j];
438 printf("Partition %u overlaps with others in "
439 "sectors %u-%u\n", i+1, starto, endo);
446 for (i = 0; i < 8; i++) {
452 qsort(array, ARRAY_SIZE(array), sizeof(array[0]),
453 (int (*)(const void *,const void *)) verify_sun_cmp);
454 if (array[0] == -1) {
455 printf("No partitions defined\n");
458 stop = g_cylinders * g_heads * g_sectors;
459 if (starts[array[0]])
460 printf("Unused gap - sectors %u-%u\n", 0, starts[array[0]]);
461 for (i = 0; i < 7 && array[i+1] != -1; i++) {
462 printf("Unused gap - sectors %u-%u\n", starts[array[i]]+lens[array[i]], starts[array[i+1]]);
464 start = starts[array[i]] + lens[array[i]];
466 printf("Unused gap - sectors %u-%u\n", start, stop);
470 add_sun_partition(int n, int sys)
472 unsigned start, stop, stop2;
473 unsigned starts[8], lens[8];
479 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
480 printf(msg_part_already_defined, n + 1);
484 fetch_sun(starts, lens, &start, &stop);
489 printf("Other partitions already cover the whole disk.\n"
490 "Delete/shrink them before retry.\n");
494 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
497 first = read_int(0, 0, 0, 0, mesg);
499 first = read_int(scround(start), scround(stop)+1,
500 scround(stop), 0, mesg);
501 if (display_in_cyl_units)
502 first *= units_per_sector;
504 /* Starting sector has to be properly aligned */
505 first = (first + g_heads * g_sectors - 1) / (g_heads * g_sectors);
506 if (n == 2 && first != 0)
508 It is highly recommended that the third partition covers the whole disk\n\
509 and is of type 'Whole disk'\n");
510 /* ewt asks to add: "don't start a partition at cyl 0"
511 However, edmundo@rano.demon.co.uk writes:
512 "In addition to having a Sun partition table, to be able to
513 boot from the disc, the first partition, /dev/sdX1, must
514 start at cylinder 0. This means that /dev/sdX1 contains
515 the partition table and the boot block, as these are the
516 first two sectors of the disc. Therefore you must be
517 careful what you use /dev/sdX1 for. In particular, you must
518 not use a partition starting at cylinder 0 for Linux swap,
519 as that would overwrite the partition table and the boot
520 block. You may, however, use such a partition for a UFS
521 or EXT2 file system, as these file systems leave the first
522 1024 bytes undisturbed. */
523 /* On the other hand, one should not use partitions
524 starting at block 0 in an md, or the label will
526 for (i = 0; i < g_partitions; i++)
527 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
529 if (i < g_partitions && !whole_disk) {
530 if (n == 2 && !first) {
534 printf("Sector %u is already allocated\n", first);
538 stop = g_cylinders * g_heads * g_sectors;
540 for (i = 0; i < g_partitions; i++) {
541 if (starts[i] > first && starts[i] < stop)
544 snprintf(mesg, sizeof(mesg),
545 "Last %s or +size or +sizeM or +sizeK",
546 str_units(SINGULAR));
548 last = read_int(scround(stop2), scround(stop2), scround(stop2),
550 else if (n == 2 && !first)
551 last = read_int(scround(first), scround(stop2), scround(stop2),
552 scround(first), mesg);
554 last = read_int(scround(first), scround(stop), scround(stop),
555 scround(first), mesg);
556 if (display_in_cyl_units)
557 last *= units_per_sector;
558 if (n == 2 && !first) {
562 } else if (last > stop) {
564 "You haven't covered the whole disk with the 3rd partition,\n"
565 "but your value %u %s covers some other partition.\n"
566 "Your entry has been changed to %u %s\n",
567 scround(last), str_units(SINGULAR),
568 scround(stop), str_units(SINGULAR));
571 } else if (!whole_disk && last > stop)
575 sys = SUN_WHOLE_DISK;
576 set_sun_partition(n, first, last, sys);
580 sun_delete_partition(int i)
585 && sunlabel->infos[i].id == SUN_WHOLE_DISK
586 && !sunlabel->partitions[i].start_cylinder
587 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == g_heads * g_sectors * g_cylinders)
588 printf("If you want to maintain SunOS/Solaris compatibility, "
589 "consider leaving this\n"
590 "partition as Whole disk (5), starting at 0, with %u "
592 sunlabel->infos[i].id = 0;
593 sunlabel->partitions[i].num_sectors = 0;
597 sun_change_sysid(int i, int sys)
599 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
601 "It is highly recommended that the partition at offset 0\n"
602 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
603 "there may destroy your partition table and bootblock.\n"
604 "Type YES if you're very sure you would like that partition\n"
605 "tagged with 82 (Linux swap): ");
606 if (strcmp (line_ptr, "YES\n"))
612 /* swaps are not mountable by default */
613 sunlabel->infos[i].flags |= 0x01;
616 /* assume other types are mountable;
617 user can change it anyway */
618 sunlabel->infos[i].flags &= ~0x01;
621 sunlabel->infos[i].id = sys;
625 sun_list_table(int xtra)
629 w = strlen(disk_device);
632 "\nDisk %s (Sun disk label): %u heads, %u sectors, %u rpm\n"
633 "%u cylinders, %u alternate cylinders, %u physical cylinders\n"
634 "%u extra sects/cyl, interleave %u:1\n"
636 "Units = %s of %u * 512 bytes\n\n",
637 disk_device, g_heads, g_sectors, SUN_SSWAP16(sunlabel->rspeed),
638 g_cylinders, SUN_SSWAP16(sunlabel->nacyl),
639 SUN_SSWAP16(sunlabel->pcylcount),
640 SUN_SSWAP16(sunlabel->sparecyl),
641 SUN_SSWAP16(sunlabel->ilfact),
643 str_units(PLURAL), units_per_sector);
646 "\nDisk %s (Sun disk label): %u heads, %u sectors, %u cylinders\n"
647 "Units = %s of %u * 512 bytes\n\n",
648 disk_device, g_heads, g_sectors, g_cylinders,
649 str_units(PLURAL), units_per_sector);
651 printf("%*s Flag Start End Blocks Id System\n",
653 for (i = 0; i < g_partitions; i++) {
654 if (sunlabel->partitions[i].num_sectors) {
655 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
656 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
657 printf("%s %c%c %9lu %9lu %9lu%c %2x %s\n",
658 partname(disk_device, i+1, w), /* device */
659 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
660 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
661 (long) scround(start), /* start */
662 (long) scround(start+len), /* end */
663 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
664 sunlabel->infos[i].id, /* type id */
665 partition_type(sunlabel->infos[i].id)); /* type name */
670 #if ENABLE_FEATURE_FDISK_ADVANCED
673 sun_set_alt_cyl(void)
676 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
677 "Number of alternate cylinders"));
681 sun_set_ncyl(int cyl)
683 sunlabel->ncyl = SUN_SSWAP16(cyl);
690 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), g_sectors, 0,
691 "Extra sectors per cylinder"));
698 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
699 "Interleave factor"));
706 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
707 "Rotation speed (rpm)"));
711 sun_set_pcylcount(void)
713 sunlabel->pcylcount =
714 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
715 "Number of physical cylinders"));
717 #endif /* FEATURE_FDISK_ADVANCED */
720 sun_write_table(void)
722 unsigned short *ush = (unsigned short *)sunlabel;
723 unsigned short csum = 0;
725 while (ush < (unsigned short *)(&sunlabel->csum))
727 sunlabel->csum = csum;
728 write_sector(0, sunlabel);
730 #endif /* SUN_LABEL */