4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2016 by Delphix. All rights reserved.
28 * This file contains the main entry point of the program and other
29 * routines relating to the general flow.
42 #include <sys/dkbad.h>
52 #include "menu_command.h"
53 #include "menu_partition.h"
58 extern struct menu_item menu_command
[];
63 * Local prototypes for ANSI C compilers
65 static void get_disk_characteristics(void);
71 * Local prototypes for non-ANSI C compilers
73 static void get_disk_characteristics();
78 * This is the main entry point.
81 main(int argc
, char *argv
[])
86 struct disk_info
*disk
= NULL
;
87 struct disk_type
*type
, *oldtype
;
88 struct partition_info
*parts
;
93 * Initialize cur_ctype to avoid null pointer dereference
94 * in auto_efi_sense().
98 * Decode the command line options.
100 i
= do_options(argc
, argv
);
102 * If we are to run from a command file, open it up.
105 if (freopen(option_f
, "r", stdin
) == NULL
) {
106 err_print("Unable to open command file '%s'.\n",
112 * If we are logging, open the log file.
115 if ((log_file
= fopen(option_l
, "w")) == NULL
) {
116 err_print("Unable to open log file '%s'.\n",
122 * Read in the data file and initialize the hardware structs.
126 * If there are no disks on the command line, search the
127 * appropriate device directory for character devices that
131 arglist
= (char **)NULL
;
133 * There were disks on the command line. They comprise the
140 * Perform the search for disks.
144 * Catch ctrl-C and ctrl-Z so critical sections can be
145 * implemented. We use sigaction, as this sets up the
146 * signal handler permanently, and also automatically
147 * restarts any interrupted system call.
149 act
.sa_handler
= cmdabort
;
150 (void) memset(&act
.sa_mask
, 0, sizeof (sigset_t
));
151 act
.sa_flags
= SA_RESTART
| SA_NODEFER
;
152 if (sigaction(SIGINT
, &act
, NULL
) == -1) {
153 err_print("sigaction(SIGINT) failed - %s\n",
158 act
.sa_handler
= onsusp
;
159 (void) memset(&act
.sa_mask
, 0, sizeof (sigset_t
));
160 act
.sa_flags
= SA_RESTART
| SA_NODEFER
;
161 if (sigaction(SIGTSTP
, &act
, NULL
) == -1) {
162 err_print("sigaction(SIGTSTP) failed - %s\n",
167 act
.sa_handler
= onalarm
;
168 (void) memset(&act
.sa_mask
, 0, sizeof (sigset_t
));
169 act
.sa_flags
= SA_RESTART
;
170 if (sigaction(SIGALRM
, &act
, NULL
) == -1) {
171 err_print("sigaction(SIGALRM) failed - %s\n",
177 * If there was only 1 disk on the command line, mark it
178 * to be the current disk. If it wasn't found, it's an error.
183 err_print("Unable to find specified disk '%s'.\n",
189 * A disk was forced on the command line.
193 * Find it in the list of found disks and mark it to
194 * be the current disk.
196 for (disk
= disk_list
; disk
!= NULL
; disk
= disk
->disk_next
)
197 if (diskname_match(option_d
, disk
))
200 * If it wasn't found, it's an error.
203 err_print("Unable to find specified disk '%s'.\n",
209 * A disk type was forced on the command line.
211 if (option_t
!= NULL
) {
213 * Only legal if a disk was also forced.
216 err_print("Must specify disk as well as type.\n");
219 oldtype
= disk
->disk_type
;
221 * Find the specified type in the list of legal types
224 for (type
= disk
->disk_ctlr
->ctlr_ctype
->ctype_dlist
;
225 type
!= NULL
; type
= type
->dtype_next
)
226 if (strcmp(option_t
, type
->dtype_asciilabel
) == 0)
229 * If it wasn't found, it's an error.
233 "Specified type '%s' is not a known type.\n", option_t
);
237 * If the specified type is not the same as the type
238 * in the disk label, update the type and nullify the
241 if (type
!= oldtype
) {
242 disk
->disk_type
= type
;
243 disk
->disk_parts
= NULL
;
247 * A partition map was forced on the command line.
251 * Only legal if both disk and type were also forced.
253 if (disk
== NULL
|| disk
->disk_type
== NULL
) {
254 err_print("Must specify disk and type as well ");
255 err_print("as partitiion.\n");
259 * Find the specified map in the list of legal maps
262 for (parts
= disk
->disk_type
->dtype_plist
; parts
!= NULL
;
263 parts
= parts
->pinfo_next
)
264 if (strcmp(option_p
, parts
->pinfo_name
) == 0)
267 * If it wasn't found, it's an error.
271 "Specified table '%s' is not a known table.\n", option_p
);
277 disk
->disk_parts
= parts
;
280 * If a disk was marked to become current, initialize the state
281 * to make it current. If not, ask user to pick one.
285 } else if (option_f
== 0 && option_d
== 0) {
293 * if -f command-file is specified, check for disk and disktype
294 * input also. For SCSI disks, the type input may not be needed
295 * since format would have figured that using inquiry information.
298 if (cur_disk
== NULL
) {
299 err_print("Must specify a disk using -d option.\n");
302 if (cur_dtype
== NULL
) {
303 err_print("Must specify disk as well as type.\n");
307 #endif /* BUG1134748 */
310 * Run the command menu.
312 cur_menu
= last_menu
= 0;
313 run_menu(menu_command
, "FORMAT", "format", 1);
316 * normal ending. Explicitly return(0);
322 * This routine initializes the internal state to ready it for a new
323 * current disk. There are a zillion state variables that store
324 * information on the current disk, and they must all be updated.
325 * We also tell SunOS about the disk, since it may not know if the
326 * disk wasn't labeled at boot time.
330 struct disk_info
*disk
;
337 caddr_t bad_ptr
= (caddr_t
)&badmap
;
341 * If there was an old current disk, close the file for it.
343 if (cur_disk
!= NULL
)
344 (void) close(cur_file
);
346 * Kill off any defect lists still lying around.
348 kill_deflist(&cur_list
);
349 kill_deflist(&work_list
);
351 * If there were any buffers, free them up.
353 if ((char *)cur_buf
!= NULL
) {
354 destroy_data((char *)cur_buf
);
357 if ((char *)pattern_buf
!= NULL
) {
358 destroy_data((char *)pattern_buf
);
362 * Fill in the hardware struct pointers for the new disk.
365 cur_dtype
= cur_disk
->disk_type
;
366 cur_label
= cur_disk
->label_type
;
367 cur_ctlr
= cur_disk
->disk_ctlr
;
368 cur_parts
= cur_disk
->disk_parts
;
369 cur_blksz
= cur_disk
->disk_lbasize
;
370 cur_ctype
= cur_ctlr
->ctlr_ctype
;
371 cur_ops
= cur_ctype
->ctype_ops
;
374 * Open a file for the new disk.
376 if ((cur_file
= open_disk(cur_disk
->disk_path
,
377 O_RDWR
| O_NDELAY
)) < 0) {
379 "Error: can't open selected disk '%s'.\n", cur_disk
->disk_name
);
384 * If the new disk uses bad-144, initialize the bad block table.
386 if (cur_ctlr
->ctlr_flags
& DKI_BAD144
) {
387 badmap
.bt_mbz
= badmap
.bt_csn
= badmap
.bt_flag
= 0;
388 for (i
= 0; i
< NDKBAD
; i
++) {
389 badmap
.bt_bad
[i
].bt_cyl
= -1;
390 badmap
.bt_bad
[i
].bt_trksec
= -1;
395 * If the type of the new disk is known...
397 if (cur_dtype
!= NULL
) {
399 * Initialize the physical characteristics.
400 * If need disk specs, prompt for undefined disk
401 * characteristics. If running from a file,
404 if (cur_dtype
->dtype_flags
& DT_NEED_SPEFS
) {
405 get_disk_characteristics();
406 cur_dtype
->dtype_flags
&= ~DT_NEED_SPEFS
;
409 ncyl
= cur_dtype
->dtype_ncyl
;
410 acyl
= cur_dtype
->dtype_acyl
;
411 pcyl
= cur_dtype
->dtype_pcyl
;
412 nhead
= cur_dtype
->dtype_nhead
;
413 nsect
= cur_dtype
->dtype_nsect
;
414 phead
= cur_dtype
->dtype_phead
;
415 psect
= cur_dtype
->dtype_psect
;
417 * Alternates per cylinder are forced to 0 or 1,
418 * independent of what the label says. This works
419 * because we know which ctlr we are dealing with.
421 if (cur_ctype
->ctype_flags
& CF_APC
)
426 * Initialize the surface analysis info. We always start
427 * out with scan set for the whole disk. Note,
428 * for SCSI disks, we can only scan the data area.
431 scan_size
= BUF_SECTS
;
432 if ((cur_ctype
->ctype_flags
& CF_SCSI
) &&
433 (cur_disk
->label_type
== L_TYPE_SOLARIS
)) {
434 scan_upper
= datasects() - 1;
435 } else if (cur_disk
->label_type
== L_TYPE_SOLARIS
) {
436 scan_upper
= physsects() - 1;
437 } else if (cur_disk
->label_type
== L_TYPE_EFI
) {
438 scan_upper
= cur_parts
->etoc
->efi_last_lba
;
442 * Allocate the buffers.
444 cur_buf
= (void *) zalloc(BUF_SECTS
* cur_blksz
);
445 pattern_buf
= (void *) zalloc(BUF_SECTS
* cur_blksz
);
448 * Tell the user which disk they selected.
450 if (chk_volname(cur_disk
)) {
451 fmt_print("selecting %s: ", cur_disk
->disk_name
);
452 print_volname(cur_disk
);
455 fmt_print("selecting %s\n", cur_disk
->disk_name
);
459 * If the drive is formatted...
461 if ((*cur_ops
->op_ck_format
)()) {
465 cur_flags
|= DISK_FORMATTED
;
467 * Read the defect list, if we have one.
469 if (!EMBEDDED_SCSI
) {
470 read_list(&cur_list
);
474 * If the disk does BAD-144, we do an ioctl to
475 * tell SunOS about the bad block table.
477 if (cur_ctlr
->ctlr_flags
& DKI_BAD144
) {
478 if (ioctl(cur_file
, HDKIOCSBAD
, &bad_ptr
)) {
480 "Warning: error telling SunOS bad block map table.\n");
484 fmt_print("[disk formatted");
485 if (!EMBEDDED_SCSI
) {
486 if (cur_list
.list
!= NULL
) {
487 fmt_print(", defect list found");
489 fmt_print(", no defect list found");
494 * Drive wasn't formatted. Tell the user in case they
497 } else if (EMBEDDED_SCSI
) {
498 fmt_print("[disk unformatted]");
501 * Make sure the user is serious. Note, for
502 * SCSI disks since this is instantaneous, we
503 * will just do it and not ask for confirmation.
506 if (!(cur_ctype
->ctype_flags
& CF_CONFIRM
)) {
508 Ready to get manufacturer's defect list from unformatted drive.\n\
509 This cannot be interrupted and takes a long while.\n\
514 "Extracting manufacturer's defect list...");
517 * Extract manufacturer's defect list.
519 if ((status
== 0) && (cur_ops
->op_ex_man
!= NULL
)) {
520 status
= (*cur_ops
->op_ex_man
)(&cur_list
);
524 fmt_print("[disk unformatted");
526 fmt_print(", no defect list found]");
528 fmt_print(", defect list found]");
533 * Disk type is not known.
534 * Initialize physical characteristics to 0 and tell the
535 * user we don't know what type the disk is.
537 ncyl
= acyl
= nhead
= nsect
= psect
= 0;
543 * Check to see if there are any mounted file systems on the
544 * disk. If there are, print a warning.
546 if ((found_mount
= checkmount((diskaddr_t
)-1, (diskaddr_t
)-1)) != 0)
547 err_print("Warning: Current Disk has mounted partitions.\n");
550 * If any part of this device is also part of an SVM, VxVM or
551 * Live Upgrade device, print a warning.
553 found_inuse
= checkdevinuse(cur_disk
->disk_name
, (diskaddr_t
)-1,
554 (diskaddr_t
)-1, 1, 0);
557 * Get the Solaris Fdisk Partition information
559 (void) copy_solaris_part(&cur_disk
->fdisk_part
);
561 if (!found_mount
&& !found_inuse
&&
562 cur_disk
->label_type
== L_TYPE_EFI
) {
565 * If alter_lba is 1, we are using the backup label.
566 * Since we can locate the backup label by disk capacity,
567 * there must be no space expanded after backup label.
569 if ((cur_parts
->etoc
->efi_altern_lba
!= 1) &&
570 (cur_parts
->etoc
->efi_altern_lba
<
571 cur_parts
->etoc
->efi_last_lba
)) {
574 * Lun expansion detected. Prompt user now and actually
575 * adjust the label in <partition> command.
578 "Note: capacity in disk label is smaller than the real disk capacity.\n\
579 Select <partition> <expand> to adjust the label capacity. \n");
586 * Prompt for some undefined disk characteristics.
587 * Used when there is no disk definition, but the
588 * disk has a valid label, so basically we're
589 * prompting for everything that isn't in the label.
592 get_disk_characteristics()
595 * The need_spefs flag is used to tell us that this disk
596 * is not a known type and the ctlr specific info must
597 * be prompted for. We only prompt for the info that applies
600 assert(cur_dtype
->dtype_flags
& DT_NEED_SPEFS
);
603 * If we're running with input from a file, use
604 * reasonable defaults, since prompting for the
605 * information will probably mess things up.
608 cur_dtype
->dtype_pcyl
= ncyl
+ acyl
;
609 cur_dtype
->dtype_rpm
= AVG_RPM
;
610 cur_dtype
->dtype_bpt
= INFINITY
;
611 cur_dtype
->dtype_phead
= 0;
612 cur_dtype
->dtype_psect
= 0;
613 cur_dtype
->dtype_cyl_skew
= 0;
614 cur_dtype
->dtype_trk_skew
= 0;
615 cur_dtype
->dtype_trks_zone
= 0;
616 cur_dtype
->dtype_atrks
= 0;
617 cur_dtype
->dtype_asect
= 0;
618 cur_dtype
->dtype_cache
= 0;
619 cur_dtype
->dtype_threshold
= 0;
620 cur_dtype
->dtype_prefetch_min
= 0;
621 cur_dtype
->dtype_prefetch_max
= 0;
623 if (cur_ctype
->ctype_flags
& CF_SMD_DEFS
) {
624 cur_dtype
->dtype_bps
= AVG_BPS
;
628 cur_dtype
->dtype_pcyl
= get_pcyl(ncyl
, cur_dtype
->dtype_acyl
);
629 cur_dtype
->dtype_bpt
= get_bpt(cur_dtype
->dtype_nsect
,
630 &cur_dtype
->dtype_options
);
631 cur_dtype
->dtype_rpm
= get_rpm();
632 cur_dtype
->dtype_fmt_time
=
633 get_fmt_time(&cur_dtype
->dtype_options
);
634 cur_dtype
->dtype_cyl_skew
=
635 get_cyl_skew(&cur_dtype
->dtype_options
);
636 cur_dtype
->dtype_trk_skew
=
637 get_trk_skew(&cur_dtype
->dtype_options
);
638 cur_dtype
->dtype_trks_zone
=
639 get_trks_zone(&cur_dtype
->dtype_options
);
640 cur_dtype
->dtype_atrks
= get_atrks(&cur_dtype
->dtype_options
);
641 cur_dtype
->dtype_asect
= get_asect(&cur_dtype
->dtype_options
);
642 cur_dtype
->dtype_cache
= get_cache(&cur_dtype
->dtype_options
);
643 cur_dtype
->dtype_threshold
=
644 get_threshold(&cur_dtype
->dtype_options
);
645 cur_dtype
->dtype_prefetch_min
=
646 get_min_prefetch(&cur_dtype
->dtype_options
);
647 cur_dtype
->dtype_prefetch_max
=
648 get_max_prefetch(cur_dtype
->dtype_prefetch_min
,
649 &cur_dtype
->dtype_options
);
650 cur_dtype
->dtype_phead
=
651 get_phead(nhead
, &cur_dtype
->dtype_options
);
652 cur_dtype
->dtype_psect
= get_psect(&cur_dtype
->dtype_options
);
653 cur_dtype
->dtype_bps
= get_bps();
655 cur_dtype
->dtype_dr_type
= 0;