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 tarball for details.
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 int sun_other_endian;
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, uint start, uint 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) {
102 current_label_type = LABEL_DOS;
103 sun_other_endian = 0;
106 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
107 ush = ((unsigned short *) (sunlabel + 1)) - 1;
108 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
110 printf("Detected sun disklabel with wrong checksum.\n"
111 "Probably you'll have to set all the values,\n"
112 "e.g. heads, sectors, cylinders and partitions\n"
113 "or force a fresh label (s command in main menu)\n");
115 g_heads = SUN_SSWAP16(sunlabel->ntrks);
116 g_cylinders = SUN_SSWAP16(sunlabel->ncyl);
117 g_sectors = SUN_SSWAP16(sunlabel->nsect);
120 current_label_type = LABEL_SUN;
125 static const struct sun_predefined_drives {
128 unsigned short sparecyl;
130 unsigned short nacyl;
131 unsigned short pcylcount;
132 unsigned short ntrks;
133 unsigned short nsect;
134 unsigned short rspeed;
136 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
137 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
138 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
139 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
140 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
141 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
142 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
143 { "","SUN0104",1,974,2,1019,6,35,3662},
144 { "","SUN0207",4,1254,2,1272,9,36,3600},
145 { "","SUN0327",3,1545,2,1549,9,46,3600},
146 { "","SUN0340",0,1538,2,1544,6,72,4200},
147 { "","SUN0424",2,1151,2,2500,9,80,4400},
148 { "","SUN0535",0,1866,2,2500,7,80,5400},
149 { "","SUN0669",5,1614,2,1632,15,54,3600},
150 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
151 { "","SUN1.05",0,2036,2,2038,14,72,5400},
152 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
153 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
154 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
157 static const struct sun_predefined_drives *
158 sun_autoconfigure_scsi(void)
160 const struct sun_predefined_drives *p = NULL;
162 #ifdef SCSI_IOCTL_GET_IDLUN
172 if (ioctl(dev_fd, SCSI_IOCTL_GET_IDLUN, &id))
176 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
177 /* This is very wrong (works only if you have one HBA),
178 but I haven't found a way how to get hostno
179 from the current kernel */
185 pfd = fopen_for_read("/proc/scsi/scsi");
189 while (fgets(buffer2, 2048, pfd)) {
190 if (strcmp(buffer, buffer2))
192 if (!fgets(buffer2, 2048, pfd))
194 q = strstr(buffer2, "Vendor: ");
200 *q++ = '\0'; /* truncate vendor name */
201 q = strstr(q, "Model: ");
207 q = strstr(q, " Rev: ");
211 for (i = 0; i < ARRAY_SIZE(sun_drives); i++) {
212 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
214 if (!strstr(model, sun_drives[i].model))
216 printf("Autoconfigure found a %s%s%s\n",
217 sun_drives[i].vendor,
218 (*sun_drives[i].vendor) ? " " : "",
219 sun_drives[i].model);
231 create_sunlabel(void)
233 struct hd_geometry geometry;
236 const struct sun_predefined_drives *p = NULL;
238 printf(msg_building_new_label, "sun disklabel");
240 sun_other_endian = BB_LITTLE_ENDIAN;
241 memset(MBRbuffer, 0, sizeof(MBRbuffer));
242 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
246 " ? auto configure\n"
247 " 0 custom (with hardware detected defaults)");
248 for (i = 0; i < ARRAY_SIZE(sun_drives); i++) {
249 printf(" %c %s%s%s\n",
250 i + 'a', sun_drives[i].vendor,
251 (*sun_drives[i].vendor) ? " " : "",
252 sun_drives[i].model);
255 c = read_nonempty("Select type (? for auto, 0 for custom): ");
259 if (c >= 'a' && c < 'a' + ARRAY_SIZE(sun_drives)) {
260 p = sun_drives + c - 'a';
263 if (c >= 'A' && c < 'A' + ARRAY_SIZE(sun_drives)) {
264 p = sun_drives + c - 'A';
267 if (c == '?' && scsi_disk) {
268 p = sun_autoconfigure_scsi();
271 printf("Autoconfigure failed\n");
276 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
277 g_heads = geometry.heads;
278 g_sectors = geometry.sectors;
279 g_cylinders = geometry.cylinders;
287 sunlabel->pcylcount = SUN_SSWAP16(g_cylinders);
288 sunlabel->rspeed = SUN_SSWAP16(300);
289 sunlabel->ilfact = SUN_SSWAP16(1);
290 sunlabel->sparecyl = 0;
292 g_heads = read_int(1, g_heads, 1024, 0, "Heads");
293 g_sectors = read_int(1, g_sectors, 1024, 0, "Sectors/track");
295 g_cylinders = read_int(1, g_cylinders - 2, 65535, 0, "Cylinders");
297 g_cylinders = read_int(1, 0, 65535, 0, "Cylinders");
298 sunlabel->nacyl = SUN_SSWAP16(read_int(0, 2, 65535, 0, "Alternate cylinders"));
299 sunlabel->pcylcount = SUN_SSWAP16(read_int(0, g_cylinders + SUN_SSWAP16(sunlabel->nacyl), 65535, 0, "Physical cylinders"));
300 sunlabel->rspeed = SUN_SSWAP16(read_int(1, 5400, 100000, 0, "Rotation speed (rpm)"));
301 sunlabel->ilfact = SUN_SSWAP16(read_int(1, 1, 32, 0, "Interleave factor"));
302 sunlabel->sparecyl = SUN_SSWAP16(read_int(0, 0, g_sectors, 0, "Extra sectors per cylinder"));
305 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
306 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
307 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
308 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
309 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
310 sunlabel->nsect = SUN_SSWAP16(p->nsect);
311 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
312 sunlabel->ilfact = SUN_SSWAP16(1);
313 g_cylinders = p->ncyl;
315 g_sectors = p->nsect;
316 puts("You may change all the disk params from the x menu");
319 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
320 "%s%s%s cyl %d alt %d hd %d sec %d",
321 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
322 p ? p->model : (floppy ? "3,5\" floppy" : "Linux custom"),
323 g_cylinders, SUN_SSWAP16(sunlabel->nacyl), g_heads, g_sectors);
325 sunlabel->ntrks = SUN_SSWAP16(g_heads);
326 sunlabel->nsect = SUN_SSWAP16(g_sectors);
327 sunlabel->ncyl = SUN_SSWAP16(g_cylinders);
329 set_sun_partition(0, 0, g_cylinders * g_heads * g_sectors, LINUX_NATIVE);
331 if (g_cylinders * g_heads * g_sectors >= 150 * 2048) {
332 ndiv = g_cylinders - (50 * 2048 / (g_heads * g_sectors)); /* 50M swap */
334 ndiv = g_cylinders * 2 / 3;
335 set_sun_partition(0, 0, ndiv * g_heads * g_sectors, LINUX_NATIVE);
336 set_sun_partition(1, ndiv * g_heads * g_sectors, g_cylinders * g_heads * g_sectors, LINUX_SWAP);
337 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
339 set_sun_partition(2, 0, g_cylinders * g_heads * g_sectors, SUN_WHOLE_DISK);
341 unsigned short *ush = (unsigned short *)sunlabel;
342 unsigned short csum = 0;
343 while (ush < (unsigned short *)(&sunlabel->csum))
345 sunlabel->csum = csum;
350 get_boot(CREATE_EMPTY_SUN);
354 toggle_sunflags(int i, unsigned char mask)
356 if (sunlabel->infos[i].flags & mask)
357 sunlabel->infos[i].flags &= ~mask;
359 sunlabel->infos[i].flags |= mask;
364 fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
366 int i, continuous = 1;
369 *stop = g_cylinders * g_heads * g_sectors;
370 for (i = 0; i < g_partitions; i++) {
371 if (sunlabel->partitions[i].num_sectors
372 && sunlabel->infos[i].id
373 && sunlabel->infos[i].id != SUN_WHOLE_DISK) {
374 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
375 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
377 if (starts[i] == *start)
379 else if (starts[i] + lens[i] >= *stop)
383 /* There will be probably more gaps
384 than one, so lets check afterwards */
393 static uint *verify_sun_starts;
396 verify_sun_cmp(int *a, int *b)
398 if (*a == -1) return 1;
399 if (*b == -1) return -1;
400 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
407 uint starts[8], lens[8], start, stop;
408 int i,j,k,starto,endo;
411 verify_sun_starts = starts;
412 fetch_sun(starts, lens, &start, &stop);
413 for (k = 0; k < 7; k++) {
414 for (i = 0; i < 8; i++) {
415 if (k && (lens[i] % (g_heads * g_sectors))) {
416 printf("Partition %d doesn't end on cylinder boundary\n", i+1);
419 for (j = 0; j < i; j++)
421 if (starts[j] == starts[i]+lens[i]) {
422 starts[j] = starts[i]; lens[j] += lens[i];
424 } else if (starts[i] == starts[j]+lens[j]){
428 if (starts[i] < starts[j]+lens[j]
429 && starts[j] < starts[i]+lens[i]) {
431 if (starts[j] > starto)
433 endo = starts[i]+lens[i];
434 if (starts[j]+lens[j] < endo)
435 endo = starts[j]+lens[j];
436 printf("Partition %d overlaps with others in "
437 "sectors %d-%d\n", i+1, starto, endo);
444 for (i = 0; i < 8; i++) {
450 qsort(array, ARRAY_SIZE(array), sizeof(array[0]),
451 (int (*)(const void *,const void *)) verify_sun_cmp);
452 if (array[0] == -1) {
453 printf("No partitions defined\n");
456 stop = g_cylinders * g_heads * g_sectors;
457 if (starts[array[0]])
458 printf("Unused gap - sectors 0-%d\n", starts[array[0]]);
459 for (i = 0; i < 7 && array[i+1] != -1; i++) {
460 printf("Unused gap - sectors %d-%d\n", starts[array[i]]+lens[array[i]], starts[array[i+1]]);
462 start = starts[array[i]] + lens[array[i]];
464 printf("Unused gap - sectors %d-%d\n", start, stop);
468 add_sun_partition(int n, int sys)
470 uint start, stop, stop2;
471 uint starts[8], lens[8];
477 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
478 printf(msg_part_already_defined, n + 1);
482 fetch_sun(starts,lens,&start,&stop);
487 printf("Other partitions already cover the whole disk.\n"
488 "Delete/shrink them before retry.\n");
492 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
495 first = read_int(0, 0, 0, 0, mesg);
497 first = read_int(scround(start), scround(stop)+1,
498 scround(stop), 0, mesg);
499 if (display_in_cyl_units)
500 first *= units_per_sector;
502 /* Starting sector has to be properly aligned */
503 first = (first + g_heads * g_sectors - 1) / (g_heads * g_sectors);
504 if (n == 2 && first != 0)
506 It is highly recommended that the third partition covers the whole disk\n\
507 and is of type 'Whole disk'\n");
508 /* ewt asks to add: "don't start a partition at cyl 0"
509 However, edmundo@rano.demon.co.uk writes:
510 "In addition to having a Sun partition table, to be able to
511 boot from the disc, the first partition, /dev/sdX1, must
512 start at cylinder 0. This means that /dev/sdX1 contains
513 the partition table and the boot block, as these are the
514 first two sectors of the disc. Therefore you must be
515 careful what you use /dev/sdX1 for. In particular, you must
516 not use a partition starting at cylinder 0 for Linux swap,
517 as that would overwrite the partition table and the boot
518 block. You may, however, use such a partition for a UFS
519 or EXT2 file system, as these file systems leave the first
520 1024 bytes undisturbed. */
521 /* On the other hand, one should not use partitions
522 starting at block 0 in an md, or the label will
524 for (i = 0; i < g_partitions; i++)
525 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
527 if (i < g_partitions && !whole_disk) {
528 if (n == 2 && !first) {
532 printf("Sector %d is already allocated\n", first);
536 stop = g_cylinders * g_heads * g_sectors;
538 for (i = 0; i < g_partitions; i++) {
539 if (starts[i] > first && starts[i] < stop)
542 snprintf(mesg, sizeof(mesg),
543 "Last %s or +size or +sizeM or +sizeK",
544 str_units(SINGULAR));
546 last = read_int(scround(stop2), scround(stop2), scround(stop2),
548 else if (n == 2 && !first)
549 last = read_int(scround(first), scround(stop2), scround(stop2),
550 scround(first), mesg);
552 last = read_int(scround(first), scround(stop), scround(stop),
553 scround(first), mesg);
554 if (display_in_cyl_units)
555 last *= units_per_sector;
556 if (n == 2 && !first) {
560 } else if (last > stop) {
562 "You haven't covered the whole disk with the 3rd partition,\n"
563 "but your value %d %s covers some other partition.\n"
564 "Your entry has been changed to %d %s\n",
565 scround(last), str_units(SINGULAR),
566 scround(stop), str_units(SINGULAR));
569 } else if (!whole_disk && last > stop)
573 sys = SUN_WHOLE_DISK;
574 set_sun_partition(n, first, last, sys);
578 sun_delete_partition(int i)
583 && sunlabel->infos[i].id == SUN_WHOLE_DISK
584 && !sunlabel->partitions[i].start_cylinder
585 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == g_heads * g_sectors * g_cylinders)
586 printf("If you want to maintain SunOS/Solaris compatibility, "
587 "consider leaving this\n"
588 "partition as Whole disk (5), starting at 0, with %u "
590 sunlabel->infos[i].id = 0;
591 sunlabel->partitions[i].num_sectors = 0;
595 sun_change_sysid(int i, int sys)
597 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
599 "It is highly recommended that the partition at offset 0\n"
600 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
601 "there may destroy your partition table and bootblock.\n"
602 "Type YES if you're very sure you would like that partition\n"
603 "tagged with 82 (Linux swap): ");
604 if (strcmp (line_ptr, "YES\n"))
610 /* swaps are not mountable by default */
611 sunlabel->infos[i].flags |= 0x01;
614 /* assume other types are mountable;
615 user can change it anyway */
616 sunlabel->infos[i].flags &= ~0x01;
619 sunlabel->infos[i].id = sys;
623 sun_list_table(int xtra)
627 w = strlen(disk_device);
630 "\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
631 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
632 "%d extra sects/cyl, interleave %d:1\n"
634 "Units = %s of %d * 512 bytes\n\n",
635 disk_device, g_heads, g_sectors, SUN_SSWAP16(sunlabel->rspeed),
636 g_cylinders, SUN_SSWAP16(sunlabel->nacyl),
637 SUN_SSWAP16(sunlabel->pcylcount),
638 SUN_SSWAP16(sunlabel->sparecyl),
639 SUN_SSWAP16(sunlabel->ilfact),
641 str_units(PLURAL), units_per_sector);
644 "\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
645 "Units = %s of %d * 512 bytes\n\n",
646 disk_device, g_heads, g_sectors, g_cylinders,
647 str_units(PLURAL), units_per_sector);
649 printf("%*s Flag Start End Blocks Id System\n",
651 for (i = 0; i < g_partitions; i++) {
652 if (sunlabel->partitions[i].num_sectors) {
653 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_sectors;
654 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
655 printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
656 partname(disk_device, i+1, w), /* device */
657 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
658 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
659 (long) scround(start), /* start */
660 (long) scround(start+len), /* end */
661 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
662 sunlabel->infos[i].id, /* type id */
663 partition_type(sunlabel->infos[i].id)); /* type name */
668 #if ENABLE_FEATURE_FDISK_ADVANCED
671 sun_set_alt_cyl(void)
674 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
675 "Number of alternate cylinders"));
679 sun_set_ncyl(int cyl)
681 sunlabel->ncyl = SUN_SSWAP16(cyl);
688 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), g_sectors, 0,
689 "Extra sectors per cylinder"));
696 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
697 "Interleave factor"));
704 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
705 "Rotation speed (rpm)"));
709 sun_set_pcylcount(void)
711 sunlabel->pcylcount =
712 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
713 "Number of physical cylinders"));
715 #endif /* FEATURE_FDISK_ADVANCED */
718 sun_write_table(void)
720 unsigned short *ush = (unsigned short *)sunlabel;
721 unsigned short csum = 0;
723 while (ush < (unsigned short *)(&sunlabel->csum))
725 sunlabel->csum = csum;
726 write_sector(0, sunlabel);
728 #endif /* SUN_LABEL */