1 #ifdef CONFIG_FEATURE_SUN_LABEL
3 #define SUN_LABEL_MAGIC 0xDABE
4 #define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
5 #define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
7 #define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
10 /* Copied from linux/major.h */
11 #define FLOPPY_MAJOR 2
13 #define SCSI_IOCTL_GET_IDLUN 0x5382
18 * I think this is mostly, or entirely, due to
19 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
21 * Merged with fdisk for other architectures, aeb, June 1998.
23 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
24 * Internationalization
28 static int sun_other_endian;
40 guess_device_type(void)
44 if (fstat(fd, &bootstat) < 0) {
47 } else if (S_ISBLK(bootstat.st_mode)
48 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
49 major(bootstat.st_rdev) == IDE1_MAJOR)) {
52 } else if (S_ISBLK(bootstat.st_mode)
53 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
62 static const struct systypes sun_sys_types[] = {
63 { "\x00" "Empty" }, /* 0 */
64 { "\x01" "Boot" }, /* 1 */
65 { "\x02" "SunOS root" }, /* 2 */
66 { "\x03" "SunOS swap" }, /* SUNOS_SWAP */
67 { "\x04" "SunOS usr" }, /* 4 */
68 { "\x05" "Whole disk" }, /* SUN_WHOLE_DISK */
69 { "\x06" "SunOS stand" }, /* 6 */
70 { "\x07" "SunOS var" }, /* 7 */
71 { "\x08" "SunOS home" }, /* 8 */
72 { "\x82" "Linux swap" }, /* LINUX_SWAP */
73 { "\x83" "Linux native" }, /* LINUX_NATIVE */
74 { "\x8e" "Linux LVM" }, /* 0x8e */
75 /* New (2.2.x) raid partition with autodetect using persistent superblock */
76 { "\xfd" "Linux raid autodetect" }, /* 0xfd */
82 set_sun_partition(int i, uint start, uint stop, int sysid)
84 sunlabel->infos[i].id = sysid;
85 sunlabel->partitions[i].start_cylinder =
86 SUN_SSWAP32(start / (heads * sectors));
87 sunlabel->partitions[i].num_sectors =
88 SUN_SSWAP32(stop - start);
98 if (sunlabel->magic != SUN_LABEL_MAGIC
99 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
100 current_label_type = label_dos;
101 sun_other_endian = 0;
104 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
105 ush = ((unsigned short *) (sunlabel + 1)) - 1;
106 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
108 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
109 "Probably you'll have to set all the values,\n"
110 "e.g. heads, sectors, cylinders and partitions\n"
111 "or force a fresh label (s command in main menu)\n"));
113 heads = SUN_SSWAP16(sunlabel->ntrks);
114 cylinders = SUN_SSWAP16(sunlabel->ncyl);
115 sectors = SUN_SSWAP16(sunlabel->nsect);
118 current_label_type = label_sun;
123 static const struct sun_predefined_drives {
126 unsigned short sparecyl;
128 unsigned short nacyl;
129 unsigned short pcylcount;
130 unsigned short ntrks;
131 unsigned short nsect;
132 unsigned short rspeed;
134 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
135 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
136 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
137 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
138 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
139 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
140 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
141 { "","SUN0104",1,974,2,1019,6,35,3662},
142 { "","SUN0207",4,1254,2,1272,9,36,3600},
143 { "","SUN0327",3,1545,2,1549,9,46,3600},
144 { "","SUN0340",0,1538,2,1544,6,72,4200},
145 { "","SUN0424",2,1151,2,2500,9,80,4400},
146 { "","SUN0535",0,1866,2,2500,7,80,5400},
147 { "","SUN0669",5,1614,2,1632,15,54,3600},
148 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
149 { "","SUN1.05",0,2036,2,2038,14,72,5400},
150 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
151 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
152 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
155 static const struct sun_predefined_drives *
156 sun_autoconfigure_scsi(void)
158 const struct sun_predefined_drives *p = NULL;
160 #ifdef SCSI_IOCTL_GET_IDLUN
170 if (ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id))
174 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
175 /* This is very wrong (works only if you have one HBA),
176 but I haven't found a way how to get hostno
177 from the current kernel */
183 pfd = fopen("/proc/scsi/scsi", "r");
187 while (fgets(buffer2, 2048, pfd)) {
188 if (strcmp(buffer, buffer2))
190 if (!fgets(buffer2, 2048, pfd))
192 q = strstr(buffer2, "Vendor: ");
198 *q++ = '\0'; /* truncate vendor name */
199 q = strstr(q, "Model: ");
205 q = strstr(q, " Rev: ");
209 for (i = 0; i < SIZE(sun_drives); i++) {
210 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
212 if (!strstr(model, sun_drives[i].model))
214 printf(_("Autoconfigure found a %s%s%s\n"),
215 sun_drives[i].vendor,
216 (*sun_drives[i].vendor) ? " " : "",
217 sun_drives[i].model);
229 create_sunlabel(void)
231 struct hd_geometry geometry;
235 const struct sun_predefined_drives *p = NULL;
238 _("Building a new sun disklabel. Changes will remain in memory only,\n"
239 "until you decide to write them. After that, of course, the previous\n"
240 "content won't be recoverable.\n\n"));
241 sun_other_endian = BB_LITTLE_ENDIAN;
242 memset(MBRbuffer, 0, sizeof(MBRbuffer));
243 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
245 puts(_("Drive type\n"
246 " ? auto configure\n"
247 " 0 custom (with hardware detected defaults)"));
248 for (i = 0; i < 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): "));
256 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
257 p = sun_drives + c - 'a';
259 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
260 p = sun_drives + c - 'A';
262 } else if (c == '0') {
264 } else if (c == '?' && scsi_disk) {
265 p = sun_autoconfigure_scsi();
267 printf(_("Autoconfigure failed.\n"));
274 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
275 heads = geometry.heads;
276 sectors = geometry.sectors;
277 cylinders = geometry.cylinders;
285 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
286 sunlabel->rspeed = SUN_SSWAP16(300);
287 sunlabel->ilfact = SUN_SSWAP16(1);
288 sunlabel->sparecyl = 0;
290 heads = read_int(1,heads,1024,0,_("Heads"));
291 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
293 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
295 cylinders = read_int(1,0,65535,0,_("Cylinders"));
296 sunlabel->nacyl = SUN_SSWAP16(read_int(0,2,65535,0, _("Alternate cylinders")));
297 sunlabel->pcylcount = SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535,0, _("Physical cylinders")));
298 sunlabel->rspeed = SUN_SSWAP16(read_int(1,5400,100000,0, _("Rotation speed (rpm)")));
299 sunlabel->ilfact = SUN_SSWAP16(read_int(1,1,32,0, _("Interleave factor")));
300 sunlabel->sparecyl = SUN_SSWAP16(read_int(0,0,sectors,0, _("Extra sectors per cylinder")));
303 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
304 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
305 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
306 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
307 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
308 sunlabel->nsect = SUN_SSWAP16(p->nsect);
309 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
310 sunlabel->ilfact = SUN_SSWAP16(1);
314 puts(_("You may change all the disk params from the x menu"));
317 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
318 "%s%s%s cyl %d alt %d hd %d sec %d",
319 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
320 p ? p->model : (floppy ? _("3,5\" floppy") : _("Linux custom")),
321 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
323 sunlabel->ntrks = SUN_SSWAP16(heads);
324 sunlabel->nsect = SUN_SSWAP16(sectors);
325 sunlabel->ncyl = SUN_SSWAP16(cylinders);
327 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
329 if (cylinders * heads * sectors >= 150 * 2048) {
330 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
332 ndiv = cylinders * 2 / 3;
333 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
334 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
335 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
337 set_sun_partition(2, 0, cylinders * heads * sectors, SUN_WHOLE_DISK);
339 unsigned short *ush = (unsigned short *)sunlabel;
340 unsigned short csum = 0;
341 while (ush < (unsigned short *)(&sunlabel->csum))
343 sunlabel->csum = csum;
348 get_boot(create_empty_sun);
352 toggle_sunflags(int i, unsigned char mask)
354 if (sunlabel->infos[i].flags & mask)
355 sunlabel->infos[i].flags &= ~mask;
357 sunlabel->infos[i].flags |= mask;
362 fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
364 int i, continuous = 1;
367 *stop = cylinders * heads * sectors;
368 for (i = 0; i < partitions; i++) {
369 if (sunlabel->partitions[i].num_sectors
370 && sunlabel->infos[i].id
371 && sunlabel->infos[i].id != SUN_WHOLE_DISK) {
372 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
373 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
375 if (starts[i] == *start)
377 else if (starts[i] + lens[i] >= *stop)
381 /* There will be probably more gaps
382 than one, so lets check afterwards */
391 static uint *verify_sun_starts;
394 verify_sun_cmp(int *a, int *b)
396 if (*a == -1) return 1;
397 if (*b == -1) return -1;
398 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
405 uint starts[8], lens[8], start, stop;
406 int i,j,k,starto,endo;
409 verify_sun_starts = starts;
410 fetch_sun(starts,lens,&start,&stop);
411 for (k = 0; k < 7; k++) {
412 for (i = 0; i < 8; i++) {
413 if (k && (lens[i] % (heads * sectors))) {
414 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
417 for (j = 0; j < i; j++)
419 if (starts[j] == starts[i]+lens[i]) {
420 starts[j] = starts[i]; lens[j] += lens[i];
422 } else if (starts[i] == starts[j]+lens[j]){
426 if (starts[i] < starts[j]+lens[j]
427 && starts[j] < starts[i]+lens[i]) {
429 if (starts[j] > starto)
431 endo = starts[i]+lens[i];
432 if (starts[j]+lens[j] < endo)
433 endo = starts[j]+lens[j];
434 printf(_("Partition %d overlaps with others in "
435 "sectors %d-%d\n"), i+1, starto, endo);
442 for (i = 0; i < 8; i++) {
448 qsort(array,SIZE(array),sizeof(array[0]),
449 (int (*)(const void *,const void *)) verify_sun_cmp);
450 if (array[0] == -1) {
451 printf(_("No partitions defined\n"));
454 stop = cylinders * heads * sectors;
455 if (starts[array[0]])
456 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
457 for (i = 0; i < 7 && array[i+1] != -1; i++) {
458 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
460 start = starts[array[i]] + lens[array[i]];
462 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
466 add_sun_partition(int n, int sys)
468 uint start, stop, stop2;
469 uint starts[8], lens[8];
475 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
476 printf(_("Partition %d is already defined. Delete "
477 "it before re-adding it.\n"), n + 1);
481 fetch_sun(starts,lens,&start,&stop);
486 printf(_("Other partitions already cover the whole disk.\nDelete "
487 "some/shrink them before retry.\n"));
491 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
494 first = read_int(0, 0, 0, 0, mesg);
496 first = read_int(scround(start), scround(stop)+1,
497 scround(stop), 0, mesg);
498 if (display_in_cyl_units)
499 first *= units_per_sector;
501 /* Starting sector has to be properly aligned */
502 first = (first + heads * sectors - 1) / (heads * sectors);
503 if (n == 2 && first != 0)
505 It is highly recommended that the third partition covers the whole disk\n\
506 and is of type `Whole disk'\n");
507 /* ewt asks to add: "don't start a partition at cyl 0"
508 However, edmundo@rano.demon.co.uk writes:
509 "In addition to having a Sun partition table, to be able to
510 boot from the disc, the first partition, /dev/sdX1, must
511 start at cylinder 0. This means that /dev/sdX1 contains
512 the partition table and the boot block, as these are the
513 first two sectors of the disc. Therefore you must be
514 careful what you use /dev/sdX1 for. In particular, you must
515 not use a partition starting at cylinder 0 for Linux swap,
516 as that would overwrite the partition table and the boot
517 block. You may, however, use such a partition for a UFS
518 or EXT2 file system, as these file systems leave the first
519 1024 bytes undisturbed. */
520 /* On the other hand, one should not use partitions
521 starting at block 0 in an md, or the label will
523 for (i = 0; i < partitions; i++)
524 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
526 if (i < partitions && !whole_disk) {
527 if (n == 2 && !first) {
531 printf(_("Sector %d is already allocated\n"), first);
535 stop = cylinders * heads * sectors;
537 for (i = 0; i < partitions; i++) {
538 if (starts[i] > first && starts[i] < stop)
541 snprintf(mesg, sizeof(mesg),
542 _("Last %s or +size or +sizeM or +sizeK"),
543 str_units(SINGULAR));
545 last = read_int(scround(stop2), scround(stop2), scround(stop2),
547 else if (n == 2 && !first)
548 last = read_int(scround(first), scround(stop2), scround(stop2),
549 scround(first), mesg);
551 last = read_int(scround(first), scround(stop), scround(stop),
552 scround(first), mesg);
553 if (display_in_cyl_units)
554 last *= units_per_sector;
555 if (n == 2 && !first) {
559 } else if (last > stop) {
560 printf(_("You haven't covered the whole disk with "
561 "the 3rd partition, but your value\n"
562 "%d %s covers some other partition. "
563 "Your entry has been changed\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)) == heads * sectors * 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, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
636 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, heads, sectors, cylinders,
647 str_units(PLURAL), units_per_sector);
649 printf(_("%*s Flag Start End Blocks Id System\n"),
651 for (i = 0 ; i < partitions; i++) {
652 if (sunlabel->partitions[i].num_sectors) {
653 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * 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 #ifdef CONFIG_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), 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 /* CONFIG_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 if (lseek(fd, 0, SEEK_SET) < 0)
727 fdisk_fatal(unable_to_seek);
728 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
729 fdisk_fatal(unable_to_write);
731 #endif /* SUN_LABEL */