1 #if ENABLE_FEATURE_SUN_LABEL
4 #define SUN_WHOLE_DISK 5
6 #define SUN_LABEL_MAGIC 0xDABE
7 #define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
8 #define SUN_SSWAP16(x) (sun_other_endian ? fdisk_swap16(x) : (uint16_t)(x))
9 #define SUN_SSWAP32(x) (sun_other_endian ? fdisk_swap32(x) : (uint32_t)(x))
11 /* Copied from linux/major.h */
12 #define FLOPPY_MAJOR 2
14 #define SCSI_IOCTL_GET_IDLUN 0x5382
19 * I think this is mostly, or entirely, due to
20 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
22 * Merged with fdisk for other architectures, aeb, June 1998.
24 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
25 * Internationalization
29 static int sun_other_endian
;
41 guess_device_type(void)
45 if (fstat(fd
, &bootstat
) < 0) {
48 } else if (S_ISBLK(bootstat
.st_mode
)
49 && (major(bootstat
.st_rdev
) == IDE0_MAJOR
||
50 major(bootstat
.st_rdev
) == IDE1_MAJOR
)) {
53 } else if (S_ISBLK(bootstat
.st_mode
)
54 && major(bootstat
.st_rdev
) == FLOPPY_MAJOR
) {
63 static const char *const sun_sys_types
[] = {
64 "\x00" "Empty" , /* 0 */
65 "\x01" "Boot" , /* 1 */
66 "\x02" "SunOS root" , /* 2 */
67 "\x03" "SunOS swap" , /* SUNOS_SWAP */
68 "\x04" "SunOS usr" , /* 4 */
69 "\x05" "Whole disk" , /* SUN_WHOLE_DISK */
70 "\x06" "SunOS stand" , /* 6 */
71 "\x07" "SunOS var" , /* 7 */
72 "\x08" "SunOS home" , /* 8 */
73 "\x82" "Linux swap" , /* LINUX_SWAP */
74 "\x83" "Linux native", /* LINUX_NATIVE */
75 "\x8e" "Linux LVM" , /* 0x8e */
76 /* New (2.2.x) raid partition with autodetect using persistent superblock */
77 "\xfd" "Linux raid autodetect", /* 0xfd */
83 set_sun_partition(int i
, uint start
, uint stop
, int sysid
)
85 sunlabel
->infos
[i
].id
= sysid
;
86 sunlabel
->partitions
[i
].start_cylinder
=
87 SUN_SSWAP32(start
/ (heads
* sectors
));
88 sunlabel
->partitions
[i
].num_sectors
=
89 SUN_SSWAP32(stop
- start
);
99 if (sunlabel
->magic
!= SUN_LABEL_MAGIC
100 && sunlabel
->magic
!= SUN_LABEL_MAGIC_SWAPPED
) {
101 current_label_type
= label_dos
;
102 sun_other_endian
= 0;
105 sun_other_endian
= (sunlabel
->magic
== SUN_LABEL_MAGIC_SWAPPED
);
106 ush
= ((unsigned short *) (sunlabel
+ 1)) - 1;
107 for (csum
= 0; ush
>= (unsigned short *)sunlabel
;) csum
^= *ush
--;
109 printf("Detected sun disklabel with wrong checksum.\n"
110 "Probably you'll have to set all the values,\n"
111 "e.g. heads, sectors, cylinders and partitions\n"
112 "or force a fresh label (s command in main menu)\n");
114 heads
= SUN_SSWAP16(sunlabel
->ntrks
);
115 cylinders
= SUN_SSWAP16(sunlabel
->ncyl
);
116 sectors
= SUN_SSWAP16(sunlabel
->nsect
);
119 current_label_type
= label_sun
;
124 static const struct sun_predefined_drives
{
127 unsigned short sparecyl
;
129 unsigned short nacyl
;
130 unsigned short pcylcount
;
131 unsigned short ntrks
;
132 unsigned short nsect
;
133 unsigned short rspeed
;
135 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
136 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
137 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
138 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
139 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
140 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
141 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
142 { "","SUN0104",1,974,2,1019,6,35,3662},
143 { "","SUN0207",4,1254,2,1272,9,36,3600},
144 { "","SUN0327",3,1545,2,1549,9,46,3600},
145 { "","SUN0340",0,1538,2,1544,6,72,4200},
146 { "","SUN0424",2,1151,2,2500,9,80,4400},
147 { "","SUN0535",0,1866,2,2500,7,80,5400},
148 { "","SUN0669",5,1614,2,1632,15,54,3600},
149 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
150 { "","SUN1.05",0,2036,2,2038,14,72,5400},
151 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
152 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
153 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
156 static const struct sun_predefined_drives
*
157 sun_autoconfigure_scsi(void)
159 const struct sun_predefined_drives
*p
= NULL
;
161 #ifdef SCSI_IOCTL_GET_IDLUN
171 if (ioctl(fd
, SCSI_IOCTL_GET_IDLUN
, &id
))
175 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
176 /* This is very wrong (works only if you have one HBA),
177 but I haven't found a way how to get hostno
178 from the current kernel */
184 pfd
= fopen("/proc/scsi/scsi", "r");
188 while (fgets(buffer2
, 2048, pfd
)) {
189 if (strcmp(buffer
, buffer2
))
191 if (!fgets(buffer2
, 2048, pfd
))
193 q
= strstr(buffer2
, "Vendor: ");
199 *q
++ = '\0'; /* truncate vendor name */
200 q
= strstr(q
, "Model: ");
206 q
= strstr(q
, " Rev: ");
210 for (i
= 0; i
< ARRAY_SIZE(sun_drives
); i
++) {
211 if (*sun_drives
[i
].vendor
&& strcasecmp(sun_drives
[i
].vendor
, vendor
))
213 if (!strstr(model
, sun_drives
[i
].model
))
215 printf("Autoconfigure found a %s%s%s\n",
216 sun_drives
[i
].vendor
,
217 (*sun_drives
[i
].vendor
) ? " " : "",
218 sun_drives
[i
].model
);
230 create_sunlabel(void)
232 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
);
245 " ? auto configure\n"
246 " 0 custom (with hardware detected defaults)");
247 for (i
= 0; i
< ARRAY_SIZE(sun_drives
); i
++) {
248 printf(" %c %s%s%s\n",
249 i
+ 'a', sun_drives
[i
].vendor
,
250 (*sun_drives
[i
].vendor
) ? " " : "",
251 sun_drives
[i
].model
);
254 c
= read_nonempty("Select type (? for auto, 0 for custom): ");
258 if (c
>= 'a' && c
< 'a' + ARRAY_SIZE(sun_drives
)) {
259 p
= sun_drives
+ c
- 'a';
262 if (c
>= 'A' && c
< 'A' + ARRAY_SIZE(sun_drives
)) {
263 p
= sun_drives
+ c
- 'A';
266 if (c
== '?' && scsi_disk
) {
267 p
= sun_autoconfigure_scsi();
270 printf("Autoconfigure failed\n");
275 if (!ioctl(fd
, HDIO_GETGEO
, &geometry
)) {
276 heads
= geometry
.heads
;
277 sectors
= geometry
.sectors
;
278 cylinders
= geometry
.cylinders
;
286 sunlabel
->pcylcount
= SUN_SSWAP16(cylinders
);
287 sunlabel
->rspeed
= SUN_SSWAP16(300);
288 sunlabel
->ilfact
= SUN_SSWAP16(1);
289 sunlabel
->sparecyl
= 0;
291 heads
= read_int(1, heads
, 1024, 0, "Heads");
292 sectors
= read_int(1, sectors
, 1024, 0, "Sectors/track");
294 cylinders
= read_int(1, cylinders
-2, 65535, 0, "Cylinders");
296 cylinders
= read_int(1, 0, 65535, 0, "Cylinders");
297 sunlabel
->nacyl
= SUN_SSWAP16(read_int(0, 2, 65535, 0, "Alternate cylinders"));
298 sunlabel
->pcylcount
= SUN_SSWAP16(read_int(0, cylinders
+SUN_SSWAP16(sunlabel
->nacyl
), 65535, 0, "Physical cylinders"));
299 sunlabel
->rspeed
= SUN_SSWAP16(read_int(1, 5400, 100000, 0, "Rotation speed (rpm)"));
300 sunlabel
->ilfact
= SUN_SSWAP16(read_int(1, 1, 32, 0, "Interleave factor"));
301 sunlabel
->sparecyl
= SUN_SSWAP16(read_int(0, 0, sectors
, 0, "Extra sectors per cylinder"));
304 sunlabel
->sparecyl
= SUN_SSWAP16(p
->sparecyl
);
305 sunlabel
->ncyl
= SUN_SSWAP16(p
->ncyl
);
306 sunlabel
->nacyl
= SUN_SSWAP16(p
->nacyl
);
307 sunlabel
->pcylcount
= SUN_SSWAP16(p
->pcylcount
);
308 sunlabel
->ntrks
= SUN_SSWAP16(p
->ntrks
);
309 sunlabel
->nsect
= SUN_SSWAP16(p
->nsect
);
310 sunlabel
->rspeed
= SUN_SSWAP16(p
->rspeed
);
311 sunlabel
->ilfact
= SUN_SSWAP16(1);
315 puts("You may change all the disk params from the x menu");
318 snprintf((char *)(sunlabel
->info
), sizeof(sunlabel
->info
),
319 "%s%s%s cyl %d alt %d hd %d sec %d",
320 p
? p
->vendor
: "", (p
&& *p
->vendor
) ? " " : "",
321 p
? p
->model
: (floppy
? "3,5\" floppy" : "Linux custom"),
322 cylinders
, SUN_SSWAP16(sunlabel
->nacyl
), heads
, sectors
);
324 sunlabel
->ntrks
= SUN_SSWAP16(heads
);
325 sunlabel
->nsect
= SUN_SSWAP16(sectors
);
326 sunlabel
->ncyl
= SUN_SSWAP16(cylinders
);
328 set_sun_partition(0, 0, cylinders
* heads
* sectors
, LINUX_NATIVE
);
330 if (cylinders
* heads
* sectors
>= 150 * 2048) {
331 ndiv
= cylinders
- (50 * 2048 / (heads
* sectors
)); /* 50M swap */
333 ndiv
= cylinders
* 2 / 3;
334 set_sun_partition(0, 0, ndiv
* heads
* sectors
, LINUX_NATIVE
);
335 set_sun_partition(1, ndiv
* heads
* sectors
, cylinders
* heads
* sectors
, LINUX_SWAP
);
336 sunlabel
->infos
[1].flags
|= 0x01; /* Not mountable */
338 set_sun_partition(2, 0, cylinders
* heads
* sectors
, SUN_WHOLE_DISK
);
340 unsigned short *ush
= (unsigned short *)sunlabel
;
341 unsigned short csum
= 0;
342 while (ush
< (unsigned short *)(&sunlabel
->csum
))
344 sunlabel
->csum
= csum
;
349 get_boot(create_empty_sun
);
353 toggle_sunflags(int i
, unsigned char mask
)
355 if (sunlabel
->infos
[i
].flags
& mask
)
356 sunlabel
->infos
[i
].flags
&= ~mask
;
358 sunlabel
->infos
[i
].flags
|= mask
;
363 fetch_sun(uint
*starts
, uint
*lens
, uint
*start
, uint
*stop
)
365 int i
, continuous
= 1;
368 *stop
= cylinders
* heads
* sectors
;
369 for (i
= 0; i
< partitions
; i
++) {
370 if (sunlabel
->partitions
[i
].num_sectors
371 && sunlabel
->infos
[i
].id
372 && sunlabel
->infos
[i
].id
!= SUN_WHOLE_DISK
) {
373 starts
[i
] = SUN_SSWAP32(sunlabel
->partitions
[i
].start_cylinder
) * heads
* sectors
;
374 lens
[i
] = SUN_SSWAP32(sunlabel
->partitions
[i
].num_sectors
);
376 if (starts
[i
] == *start
)
378 else if (starts
[i
] + lens
[i
] >= *stop
)
382 /* There will be probably more gaps
383 than one, so lets check afterwards */
392 static uint
*verify_sun_starts
;
395 verify_sun_cmp(int *a
, int *b
)
397 if (*a
== -1) return 1;
398 if (*b
== -1) return -1;
399 if (verify_sun_starts
[*a
] > verify_sun_starts
[*b
]) return 1;
406 uint starts
[8], lens
[8], start
, stop
;
407 int i
,j
,k
,starto
,endo
;
410 verify_sun_starts
= starts
;
411 fetch_sun(starts
,lens
,&start
,&stop
);
412 for (k
= 0; k
< 7; k
++) {
413 for (i
= 0; i
< 8; i
++) {
414 if (k
&& (lens
[i
] % (heads
* sectors
))) {
415 printf("Partition %d doesn't end on cylinder boundary\n", i
+1);
418 for (j
= 0; j
< i
; j
++)
420 if (starts
[j
] == starts
[i
]+lens
[i
]) {
421 starts
[j
] = starts
[i
]; lens
[j
] += lens
[i
];
423 } else if (starts
[i
] == starts
[j
]+lens
[j
]){
427 if (starts
[i
] < starts
[j
]+lens
[j
]
428 && starts
[j
] < starts
[i
]+lens
[i
]) {
430 if (starts
[j
] > starto
)
432 endo
= starts
[i
]+lens
[i
];
433 if (starts
[j
]+lens
[j
] < endo
)
434 endo
= starts
[j
]+lens
[j
];
435 printf("Partition %d overlaps with others in "
436 "sectors %d-%d\n", i
+1, starto
, endo
);
443 for (i
= 0; i
< 8; i
++) {
449 qsort(array
, ARRAY_SIZE(array
), sizeof(array
[0]),
450 (int (*)(const void *,const void *)) verify_sun_cmp
);
451 if (array
[0] == -1) {
452 printf("No partitions defined\n");
455 stop
= cylinders
* heads
* sectors
;
456 if (starts
[array
[0]])
457 printf("Unused gap - sectors 0-%d\n", starts
[array
[0]]);
458 for (i
= 0; i
< 7 && array
[i
+1] != -1; i
++) {
459 printf("Unused gap - sectors %d-%d\n", starts
[array
[i
]]+lens
[array
[i
]], starts
[array
[i
+1]]);
461 start
= starts
[array
[i
]] + lens
[array
[i
]];
463 printf("Unused gap - sectors %d-%d\n", start
, stop
);
467 add_sun_partition(int n
, int sys
)
469 uint start
, stop
, stop2
;
470 uint starts
[8], lens
[8];
476 if (sunlabel
->partitions
[n
].num_sectors
&& sunlabel
->infos
[n
].id
) {
477 printf(msg_part_already_defined
, n
+ 1);
481 fetch_sun(starts
,lens
,&start
,&stop
);
486 printf("Other partitions already cover the whole disk.\n"
487 "Delete/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
) {
561 "You haven't covered the whole disk with the 3rd partition,\n"
562 "but your value %d %s covers some other partition.\n"
563 "Your entry has been changed to %d %s\n",
564 scround(last
), str_units(SINGULAR
),
565 scround(stop
), str_units(SINGULAR
));
568 } else if (!whole_disk
&& last
> stop
)
572 sys
= SUN_WHOLE_DISK
;
573 set_sun_partition(n
, first
, last
, sys
);
577 sun_delete_partition(int i
)
582 && sunlabel
->infos
[i
].id
== SUN_WHOLE_DISK
583 && !sunlabel
->partitions
[i
].start_cylinder
584 && (nsec
= SUN_SSWAP32(sunlabel
->partitions
[i
].num_sectors
)) == heads
* sectors
* cylinders
)
585 printf("If you want to maintain SunOS/Solaris compatibility, "
586 "consider leaving this\n"
587 "partition as Whole disk (5), starting at 0, with %u "
589 sunlabel
->infos
[i
].id
= 0;
590 sunlabel
->partitions
[i
].num_sectors
= 0;
594 sun_change_sysid(int i
, int sys
)
596 if (sys
== LINUX_SWAP
&& !sunlabel
->partitions
[i
].start_cylinder
) {
598 "It is highly recommended that the partition at offset 0\n"
599 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
600 "there may destroy your partition table and bootblock.\n"
601 "Type YES if you're very sure you would like that partition\n"
602 "tagged with 82 (Linux swap): ");
603 if (strcmp (line_ptr
, "YES\n"))
609 /* swaps are not mountable by default */
610 sunlabel
->infos
[i
].flags
|= 0x01;
613 /* assume other types are mountable;
614 user can change it anyway */
615 sunlabel
->infos
[i
].flags
&= ~0x01;
618 sunlabel
->infos
[i
].id
= sys
;
622 sun_list_table(int xtra
)
626 w
= strlen(disk_device
);
629 "\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
630 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
631 "%d extra sects/cyl, interleave %d:1\n"
633 "Units = %s of %d * 512 bytes\n\n",
634 disk_device
, heads
, sectors
, SUN_SSWAP16(sunlabel
->rspeed
),
635 cylinders
, SUN_SSWAP16(sunlabel
->nacyl
),
636 SUN_SSWAP16(sunlabel
->pcylcount
),
637 SUN_SSWAP16(sunlabel
->sparecyl
),
638 SUN_SSWAP16(sunlabel
->ilfact
),
640 str_units(PLURAL
), units_per_sector
);
643 "\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
644 "Units = %s of %d * 512 bytes\n\n",
645 disk_device
, heads
, sectors
, cylinders
,
646 str_units(PLURAL
), units_per_sector
);
648 printf("%*s Flag Start End Blocks Id System\n",
650 for (i
= 0; i
< partitions
; i
++) {
651 if (sunlabel
->partitions
[i
].num_sectors
) {
652 uint32_t start
= SUN_SSWAP32(sunlabel
->partitions
[i
].start_cylinder
) * heads
* sectors
;
653 uint32_t len
= SUN_SSWAP32(sunlabel
->partitions
[i
].num_sectors
);
654 printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
655 partname(disk_device
, i
+1, w
), /* device */
656 (sunlabel
->infos
[i
].flags
& 0x01) ? 'u' : ' ', /* flags */
657 (sunlabel
->infos
[i
].flags
& 0x10) ? 'r' : ' ',
658 (long) scround(start
), /* start */
659 (long) scround(start
+len
), /* end */
660 (long) len
/ 2, len
& 1 ? '+' : ' ', /* odd flag on end */
661 sunlabel
->infos
[i
].id
, /* type id */
662 partition_type(sunlabel
->infos
[i
].id
)); /* type name */
667 #if ENABLE_FEATURE_FDISK_ADVANCED
670 sun_set_alt_cyl(void)
673 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel
->nacyl
), 65535, 0,
674 "Number of alternate cylinders"));
678 sun_set_ncyl(int cyl
)
680 sunlabel
->ncyl
= SUN_SSWAP16(cyl
);
687 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel
->sparecyl
), sectors
, 0,
688 "Extra sectors per cylinder"));
695 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel
->ilfact
), 32, 0,
696 "Interleave factor"));
703 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel
->rspeed
), 100000, 0,
704 "Rotation speed (rpm)"));
708 sun_set_pcylcount(void)
710 sunlabel
->pcylcount
=
711 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel
->pcylcount
), 65535, 0,
712 "Number of physical cylinders"));
714 #endif /* FEATURE_FDISK_ADVANCED */
717 sun_write_table(void)
719 unsigned short *ush
= (unsigned short *)sunlabel
;
720 unsigned short csum
= 0;
722 while (ush
< (unsigned short *)(&sunlabel
->csum
))
724 sunlabel
->csum
= csum
;
725 if (lseek(fd
, 0, SEEK_SET
) < 0)
726 fdisk_fatal(unable_to_seek
);
727 if (write(fd
, sunlabel
, SECTOR_SIZE
) != SECTOR_SIZE
)
728 fdisk_fatal(unable_to_write
);
730 #endif /* SUN_LABEL */