xref: /onnv-gate/usr/src/cmd/format/menu_defect.c (revision 9889:68d0fe4c716e)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57563SPrasad.Singamsetty@Sun.COM  * Common Development and Distribution License (the "License").
67563SPrasad.Singamsetty@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*9889SLarry.Liu@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * This file contains functions to implement the defect menu commands.
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate #include "global.h"
300Sstevel@tonic-gate #include <unistd.h>
310Sstevel@tonic-gate #include <string.h>
320Sstevel@tonic-gate #include "misc.h"
330Sstevel@tonic-gate #include "menu_defect.h"
340Sstevel@tonic-gate #include "param.h"
350Sstevel@tonic-gate #include "ctlr_scsi.h"
360Sstevel@tonic-gate 
370Sstevel@tonic-gate /*
380Sstevel@tonic-gate  * This is the working defect list.  All the commands here operate on
390Sstevel@tonic-gate  * the working list, except for 'commit'.  This way the user can
400Sstevel@tonic-gate  * change his mind at any time without having mangled the current defect
410Sstevel@tonic-gate  * list.
420Sstevel@tonic-gate  */
430Sstevel@tonic-gate struct	defect_list work_list;
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #ifdef __STDC__
460Sstevel@tonic-gate 
470Sstevel@tonic-gate /* Function prototypes for ANSI C Compilers */
480Sstevel@tonic-gate static int	commit_list(void);
490Sstevel@tonic-gate 
500Sstevel@tonic-gate #else	/* __STDC__ */
510Sstevel@tonic-gate 
520Sstevel@tonic-gate /* Function prototypes for non-ANSI C Compilers */
530Sstevel@tonic-gate static int	commit_list();
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #endif	/* __STDC__ */
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate  * This routine implements the 'restore' command.  It sets the working
590Sstevel@tonic-gate  * list equal to the current list.
600Sstevel@tonic-gate  */
610Sstevel@tonic-gate int
d_restore()620Sstevel@tonic-gate d_restore()
630Sstevel@tonic-gate {
640Sstevel@tonic-gate 	int	i;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate 	assert(!EMBEDDED_SCSI);
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 	/*
690Sstevel@tonic-gate 	 * If the working list has not been modified, there's nothing to do.
700Sstevel@tonic-gate 	 */
710Sstevel@tonic-gate 	if (!(work_list.flags & LIST_DIRTY)) {
720Sstevel@tonic-gate 		err_print("working list was not modified.\n");
730Sstevel@tonic-gate 		return (0);
740Sstevel@tonic-gate 	}
750Sstevel@tonic-gate 	/*
760Sstevel@tonic-gate 	 * Make sure the user is serious.
770Sstevel@tonic-gate 	 */
780Sstevel@tonic-gate 	if (check("Ready to update working list, continue"))
790Sstevel@tonic-gate 		return (-1);
800Sstevel@tonic-gate 	/*
810Sstevel@tonic-gate 	 * Lock out interrupts so the lists can't get mangled.
820Sstevel@tonic-gate 	 */
830Sstevel@tonic-gate 	enter_critical();
840Sstevel@tonic-gate 	/*
850Sstevel@tonic-gate 	 * Kill off the old working list.
860Sstevel@tonic-gate 	 */
870Sstevel@tonic-gate 	kill_deflist(&work_list);
880Sstevel@tonic-gate 	/*
890Sstevel@tonic-gate 	 * If the current isn't null, set the working list to be a
900Sstevel@tonic-gate 	 * copy of it.
910Sstevel@tonic-gate 	 */
920Sstevel@tonic-gate 	if (cur_list.list != NULL) {
930Sstevel@tonic-gate 		work_list.header = cur_list.header;
940Sstevel@tonic-gate 		work_list.list = (struct defect_entry *)zalloc(
95*9889SLarry.Liu@Sun.COM 		    deflist_size(cur_blksz, work_list.header.count) *
96*9889SLarry.Liu@Sun.COM 		    cur_blksz);
970Sstevel@tonic-gate 		for (i = 0; i < work_list.header.count; i++)
980Sstevel@tonic-gate 			*(work_list.list + i) = *(cur_list.list + i);
990Sstevel@tonic-gate 	}
1000Sstevel@tonic-gate 	/*
1010Sstevel@tonic-gate 	 * Initialize the flags since they are now in sync.
1020Sstevel@tonic-gate 	 */
1030Sstevel@tonic-gate 	work_list.flags = 0;
1040Sstevel@tonic-gate 	if (work_list.list == NULL)
1050Sstevel@tonic-gate 		fmt_print("working list set to null.\n\n");
1060Sstevel@tonic-gate 	else
1070Sstevel@tonic-gate 		fmt_print("working list updated, total of %d defects.\n\n",
1080Sstevel@tonic-gate 		    work_list.header.count);
1090Sstevel@tonic-gate 	exit_critical();
1100Sstevel@tonic-gate 	return (0);
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate  * This routine implements the 'original' command.  It extracts the
1150Sstevel@tonic-gate  * manufacturer's defect list from the current disk.
1160Sstevel@tonic-gate  */
1170Sstevel@tonic-gate int
d_original()1180Sstevel@tonic-gate d_original()
1190Sstevel@tonic-gate {
1200Sstevel@tonic-gate 	int	status;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	/*
1240Sstevel@tonic-gate 	 * If the controller does not support the extraction, we're out
1250Sstevel@tonic-gate 	 * of luck.
1260Sstevel@tonic-gate 	 */
1270Sstevel@tonic-gate 	if (cur_ops->op_ex_man == NULL) {
1280Sstevel@tonic-gate 		err_print("Controller does not support extracting ");
1290Sstevel@tonic-gate 		err_print("manufacturer's defect list.\n");
1300Sstevel@tonic-gate 		return (-1);
1310Sstevel@tonic-gate 	}
1320Sstevel@tonic-gate 	/*
1330Sstevel@tonic-gate 	 * Make sure the user is serious.  Note, for SCSI disks
1340Sstevel@tonic-gate 	 * since this is instantaneous, we will just do it and
1350Sstevel@tonic-gate 	 * not ask for confirmation.
1360Sstevel@tonic-gate 	 */
1370Sstevel@tonic-gate 	if (!(cur_ctype->ctype_flags & CF_CONFIRM) &&
1380Sstevel@tonic-gate 	    check(
1390Sstevel@tonic-gate "Ready to update working list. This cannot be interrupted\n\
1400Sstevel@tonic-gate and may take a long while. Continue"))
1410Sstevel@tonic-gate 		return (-1);
1420Sstevel@tonic-gate 	/*
1430Sstevel@tonic-gate 	 * Lock out interrupts so we don't get half the list.
1440Sstevel@tonic-gate 	 */
1450Sstevel@tonic-gate 	enter_critical();
1460Sstevel@tonic-gate 	/*
1470Sstevel@tonic-gate 	 * Kill off the working list.
1480Sstevel@tonic-gate 	 */
1490Sstevel@tonic-gate 	kill_deflist(&work_list);
1500Sstevel@tonic-gate 	fmt_print("Extracting manufacturer's defect list...");
1510Sstevel@tonic-gate 	/*
1520Sstevel@tonic-gate 	 * Do the extraction.
1530Sstevel@tonic-gate 	 */
1540Sstevel@tonic-gate 	status = (*cur_ops->op_ex_man)(&work_list);
1550Sstevel@tonic-gate 	if (status)
1560Sstevel@tonic-gate 		fmt_print("Extraction failed.\n\n");
1570Sstevel@tonic-gate 	else {
1580Sstevel@tonic-gate 		fmt_print("Extraction complete.\n");
1590Sstevel@tonic-gate 		fmt_print("Working list updated, total of %d defects.\n\n",
1600Sstevel@tonic-gate 		    work_list.header.count);
1610Sstevel@tonic-gate 	}
1620Sstevel@tonic-gate 	/*
1630Sstevel@tonic-gate 	 * Mark the working list dirty since we modified it.
1640Sstevel@tonic-gate 	 */
1650Sstevel@tonic-gate 	work_list.flags |= LIST_DIRTY;
1660Sstevel@tonic-gate 	exit_critical();
1670Sstevel@tonic-gate 	/*
1680Sstevel@tonic-gate 	 * Return status.
1690Sstevel@tonic-gate 	 */
1700Sstevel@tonic-gate 	return (status);
1710Sstevel@tonic-gate }
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate /*
1740Sstevel@tonic-gate  * This routine implements the 'extract' command.  It extracts the
1750Sstevel@tonic-gate  * entire defect list from the current disk.
1760Sstevel@tonic-gate  */
1770Sstevel@tonic-gate int
d_extract()1780Sstevel@tonic-gate d_extract()
1790Sstevel@tonic-gate {
1800Sstevel@tonic-gate 	int	status;
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	/*
1830Sstevel@tonic-gate 	 * If the controller does not support the extraction, we are out
1840Sstevel@tonic-gate 	 * of luck.
1850Sstevel@tonic-gate 	 */
1860Sstevel@tonic-gate 	if (cur_ops->op_ex_cur == NULL) {
1870Sstevel@tonic-gate 		err_print("Controller does not support extracting ");
1880Sstevel@tonic-gate 		err_print("current defect list.\n");
1890Sstevel@tonic-gate 		return (-1);
1900Sstevel@tonic-gate 	}
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	/*
1930Sstevel@tonic-gate 	 * If disk is unformatted, you really shouldn't do this.
1940Sstevel@tonic-gate 	 * However, ask user to be sure.
1950Sstevel@tonic-gate 	 */
1960Sstevel@tonic-gate 	if (! (cur_flags & DISK_FORMATTED) &&
1970Sstevel@tonic-gate 	    (check(
1980Sstevel@tonic-gate "Cannot extract defect list from an unformatted disk. Continue")))
1990Sstevel@tonic-gate 		return (-1);
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	/*
2020Sstevel@tonic-gate 	 * If this takes a long time, let's ask the user if he
2030Sstevel@tonic-gate 	 * doesn't mind waiting.  Note, for SCSI disks
2040Sstevel@tonic-gate 	 * this operation is instantaneous so we won't ask for
2050Sstevel@tonic-gate 	 * for confirmation.
2060Sstevel@tonic-gate 	 */
2070Sstevel@tonic-gate 	if (! (cur_ctype->ctype_flags & CF_CONFIRM) &&
2080Sstevel@tonic-gate 	    check(
2090Sstevel@tonic-gate "Ready to extract working list. This cannot be interrupted\n\
2100Sstevel@tonic-gate and may take a long while. Continue"))
2110Sstevel@tonic-gate 		return (-1);
2120Sstevel@tonic-gate 	/*
2130Sstevel@tonic-gate 	 * Lock out interrupts so we don't get half the list and
2140Sstevel@tonic-gate 	 * Kill off the working list.
2150Sstevel@tonic-gate 	 */
2160Sstevel@tonic-gate 	enter_critical();
2170Sstevel@tonic-gate 	kill_deflist(&work_list);
2180Sstevel@tonic-gate 	fmt_print("Extracting defect list...");
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	/*
2210Sstevel@tonic-gate 	 * Do the extraction.
2220Sstevel@tonic-gate 	 */
2230Sstevel@tonic-gate 	status = (*cur_ops->op_ex_cur)(&work_list);
2240Sstevel@tonic-gate 	if (status) {
2250Sstevel@tonic-gate 		if (!EMBEDDED_SCSI) {
2260Sstevel@tonic-gate 			if (cur_flags & DISK_FORMATTED)
2270Sstevel@tonic-gate 				read_list(&work_list);
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 			if (work_list.list != NULL) {
2300Sstevel@tonic-gate 				status = 0;
2310Sstevel@tonic-gate 				fmt_print("Extraction complete.\n");
2320Sstevel@tonic-gate 				fmt_print(
2330Sstevel@tonic-gate "Working list updated, total of %d defects.\n\n",
234*9889SLarry.Liu@Sun.COM 				    work_list.header.count);
2350Sstevel@tonic-gate 			} else {
2360Sstevel@tonic-gate 				fmt_print("Extraction failed.\n\n");
2370Sstevel@tonic-gate 			}
2380Sstevel@tonic-gate 		} else {
2390Sstevel@tonic-gate 			fmt_print("Extraction failed.\n\n");
2400Sstevel@tonic-gate 		}
2410Sstevel@tonic-gate 	} else {
2420Sstevel@tonic-gate 		fmt_print("Extraction complete.\n");
2430Sstevel@tonic-gate 		fmt_print("Working list updated, total of %d defects.\n\n",
2440Sstevel@tonic-gate 		    work_list.header.count);
2450Sstevel@tonic-gate 	}
2460Sstevel@tonic-gate 	/*
2470Sstevel@tonic-gate 	 * Mark the working list dirty since we modified it.
2480Sstevel@tonic-gate 	 */
2490Sstevel@tonic-gate 	work_list.flags |= LIST_DIRTY;
2500Sstevel@tonic-gate 	exit_critical();
2510Sstevel@tonic-gate 	/*
2520Sstevel@tonic-gate 	 * Return status.
2530Sstevel@tonic-gate 	 */
2540Sstevel@tonic-gate 	return (status);
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate /*
2580Sstevel@tonic-gate  * This routine implements the 'add' command.  It allows the user to
2590Sstevel@tonic-gate  * enter the working defect list manually.  It loops infinitely until
2600Sstevel@tonic-gate  * the user breaks out with a ctrl-C.
2610Sstevel@tonic-gate  */
2620Sstevel@tonic-gate int
d_add()2630Sstevel@tonic-gate d_add()
2640Sstevel@tonic-gate {
2657563SPrasad.Singamsetty@Sun.COM 	int			type, deflt, index;
2667563SPrasad.Singamsetty@Sun.COM 	diskaddr_t		bn;
2670Sstevel@tonic-gate 	u_ioparam_t		ioparam;
2680Sstevel@tonic-gate 	struct defect_entry	def;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	assert(!EMBEDDED_SCSI);
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	/*
2730Sstevel@tonic-gate 	 * Ask the user which mode of input he'd like to use.
2740Sstevel@tonic-gate 	 */
2750Sstevel@tonic-gate 	fmt_print("        0. bytes-from-index\n");
2760Sstevel@tonic-gate 	fmt_print("        1. logical block\n");
2770Sstevel@tonic-gate 	deflt = 0;
2780Sstevel@tonic-gate 	ioparam.io_bounds.lower = 0;
2790Sstevel@tonic-gate 	ioparam.io_bounds.upper = 1;
2800Sstevel@tonic-gate 	type = input(FIO_INT, "Select input format (enter its number)", ':',
281*9889SLarry.Liu@Sun.COM 	    &ioparam, &deflt, DATA_INPUT);
2820Sstevel@tonic-gate 	fmt_print("\nEnter Control-C to terminate.\n");
2830Sstevel@tonic-gate loop:
2840Sstevel@tonic-gate 	if (type) {
2850Sstevel@tonic-gate 		/*
2860Sstevel@tonic-gate 		 * Mode selected is logical block.  Input the defective block
2870Sstevel@tonic-gate 		 * and fill in the defect entry with the info.
2880Sstevel@tonic-gate 		 */
2890Sstevel@tonic-gate 		def.bfi = def.nbits = UNKNOWN;
2900Sstevel@tonic-gate 		ioparam.io_bounds.lower = 0;
2910Sstevel@tonic-gate 		if (cur_disk->label_type == L_TYPE_SOLARIS) {
292*9889SLarry.Liu@Sun.COM 			ioparam.io_bounds.upper = physsects() - 1;
2930Sstevel@tonic-gate 		} else {
294*9889SLarry.Liu@Sun.COM 			ioparam.io_bounds.upper = cur_parts->etoc->efi_last_lba;
2950Sstevel@tonic-gate 		}
2960Sstevel@tonic-gate 		bn = input(FIO_BN, "Enter defective block number", ':',
2970Sstevel@tonic-gate 		    &ioparam, (int *)NULL, DATA_INPUT);
2980Sstevel@tonic-gate 		def.cyl = bn2c(bn);
2990Sstevel@tonic-gate 		def.head = bn2h(bn);
3000Sstevel@tonic-gate 		def.sect = bn2s(bn);
3010Sstevel@tonic-gate 	} else {
3020Sstevel@tonic-gate 		/*
3030Sstevel@tonic-gate 		 * Mode selected is bytes-from-index.  Input the information
3040Sstevel@tonic-gate 		 * about the defect and fill in the defect entry.
3050Sstevel@tonic-gate 		 */
3060Sstevel@tonic-gate 		def.sect = UNKNOWN;
3070Sstevel@tonic-gate 		ioparam.io_bounds.lower = 0;
3080Sstevel@tonic-gate 		ioparam.io_bounds.upper = pcyl - 1;
3090Sstevel@tonic-gate 		def.cyl = input(FIO_INT,
3100Sstevel@tonic-gate 		    "Enter defect's cylinder number", ':',
3110Sstevel@tonic-gate 		    &ioparam, (int *)NULL, DATA_INPUT);
3120Sstevel@tonic-gate 		ioparam.io_bounds.upper = nhead - 1;
3130Sstevel@tonic-gate 		def.head = input(FIO_INT, "Enter defect's head number",
3140Sstevel@tonic-gate 		    ':', &ioparam, (int *)NULL, DATA_INPUT);
3150Sstevel@tonic-gate 		ioparam.io_bounds.upper = cur_dtype->dtype_bpt - 1;
3160Sstevel@tonic-gate 		def.bfi = input(FIO_INT, "Enter defect's bytes-from-index",
3170Sstevel@tonic-gate 		    ':', &ioparam, (int *)NULL, DATA_INPUT);
3180Sstevel@tonic-gate 		ioparam.io_bounds.lower = -1;
3190Sstevel@tonic-gate 		ioparam.io_bounds.upper = (cur_dtype->dtype_bpt - def.bfi) * 8;
3200Sstevel@tonic-gate 		if (ioparam.io_bounds.upper >= 32 * 1024)
3210Sstevel@tonic-gate 			ioparam.io_bounds.upper = 32 * 1024 - 1;
3220Sstevel@tonic-gate 		/*
3230Sstevel@tonic-gate 		 * Note: a length of -1 means the length is not known.  We
3240Sstevel@tonic-gate 		 * make this the default value.
3250Sstevel@tonic-gate 		 */
3260Sstevel@tonic-gate 		deflt = -1;
3270Sstevel@tonic-gate 		def.nbits = input(FIO_INT, "Enter defect's length (in bits)",
3280Sstevel@tonic-gate 		    ':', &ioparam, &deflt, DATA_INPUT);
3290Sstevel@tonic-gate 	}
3300Sstevel@tonic-gate 	/*
3310Sstevel@tonic-gate 	 * Calculate where in the defect list this defect belongs
3320Sstevel@tonic-gate 	 * and print it out.
3330Sstevel@tonic-gate 	 */
3340Sstevel@tonic-gate 	index = sort_defect(&def, &work_list);
3350Sstevel@tonic-gate 	fmt_print(DEF_PRINTHEADER);
3360Sstevel@tonic-gate 	pr_defect(&def, index);
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	/*
3390Sstevel@tonic-gate 	 * Lock out interrupts so lists don't get mangled.
3400Sstevel@tonic-gate 	 * Also, mark the working list dirty since we are modifying it.
3410Sstevel@tonic-gate 	 */
3420Sstevel@tonic-gate 	enter_critical();
3430Sstevel@tonic-gate 	work_list.flags |= LIST_DIRTY;
3440Sstevel@tonic-gate 	/*
3450Sstevel@tonic-gate 	 * If the list is null, create it with zero length.  This is
3460Sstevel@tonic-gate 	 * necessary because the routines to add a defect to the list
3470Sstevel@tonic-gate 	 * assume the list is initialized.
3480Sstevel@tonic-gate 	 */
3490Sstevel@tonic-gate 	if (work_list.list == NULL) {
3500Sstevel@tonic-gate 		work_list.header.magicno = (uint_t)DEFECT_MAGIC;
3510Sstevel@tonic-gate 		work_list.header.count = 0;
3520Sstevel@tonic-gate 		work_list.list = (struct defect_entry *)zalloc(
353*9889SLarry.Liu@Sun.COM 		    deflist_size(cur_blksz, 0) * cur_blksz);
3540Sstevel@tonic-gate 	}
3550Sstevel@tonic-gate 	/*
3560Sstevel@tonic-gate 	 * Add the defect to the working list.
3570Sstevel@tonic-gate 	 */
3580Sstevel@tonic-gate 	add_def(&def, &work_list, index);
3590Sstevel@tonic-gate 	fmt_print("defect number %d added.\n\n", index + 1);
3600Sstevel@tonic-gate 	exit_critical();
3610Sstevel@tonic-gate 	/*
3620Sstevel@tonic-gate 	 * Loop back for the next defect.
3630Sstevel@tonic-gate 	 */
3640Sstevel@tonic-gate 	goto loop;
3650Sstevel@tonic-gate 	/*NOTREACHED*/
3660Sstevel@tonic-gate #ifdef	lint
3670Sstevel@tonic-gate 	return (0);
3680Sstevel@tonic-gate #endif
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate /*
3720Sstevel@tonic-gate  * This routine implements the 'delete' command.  It allows the user
3730Sstevel@tonic-gate  * to manually delete a defect from the working list.
3740Sstevel@tonic-gate  */
3750Sstevel@tonic-gate int
d_delete()3760Sstevel@tonic-gate d_delete()
3770Sstevel@tonic-gate {
3780Sstevel@tonic-gate 	int		i, count, num;
3790Sstevel@tonic-gate 	u_ioparam_t	ioparam;
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	assert(!EMBEDDED_SCSI);
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	/*
3840Sstevel@tonic-gate 	 * If the working list is null or zero length, there's nothing
3850Sstevel@tonic-gate 	 * to delete.
3860Sstevel@tonic-gate 	 */
3870Sstevel@tonic-gate 	count = work_list.header.count;
3880Sstevel@tonic-gate 	if (work_list.list == NULL || count == 0) {
3890Sstevel@tonic-gate 		err_print("No defects to delete.\n");
3900Sstevel@tonic-gate 		return (-1);
3910Sstevel@tonic-gate 	}
3920Sstevel@tonic-gate 	/*
3930Sstevel@tonic-gate 	 * Ask the user which defect should be deleted. Bounds are off by
3940Sstevel@tonic-gate 	 * one because user sees a one-relative list.
3950Sstevel@tonic-gate 	 */
3960Sstevel@tonic-gate 	ioparam.io_bounds.lower = 1;
3970Sstevel@tonic-gate 	ioparam.io_bounds.upper = count;
3980Sstevel@tonic-gate 	num = input(FIO_INT, "Specify defect to be deleted (enter its number)",
3990Sstevel@tonic-gate 	    ':', &ioparam, (int *)NULL, DATA_INPUT);
4000Sstevel@tonic-gate 	/*
4010Sstevel@tonic-gate 	 *
4020Sstevel@tonic-gate 	 * The user thinks it's one relative but it's not really.
4030Sstevel@tonic-gate 	 */
4040Sstevel@tonic-gate 	--num;
4050Sstevel@tonic-gate 	/*
4060Sstevel@tonic-gate 	 * Print the defect selected and ask the user for confirmation.
4070Sstevel@tonic-gate 	 */
4080Sstevel@tonic-gate 	fmt_print(DEF_PRINTHEADER);
4090Sstevel@tonic-gate 	pr_defect(work_list.list + num, num);
4100Sstevel@tonic-gate 	/*
4110Sstevel@tonic-gate 	 * Lock out interrupts so the lists don't get mangled.
4120Sstevel@tonic-gate 	 */
4130Sstevel@tonic-gate 	enter_critical();
4140Sstevel@tonic-gate 	/*
4150Sstevel@tonic-gate 	 * Move down all the defects beyond the one deleted so the defect
4160Sstevel@tonic-gate 	 * list is still fully populated.
4170Sstevel@tonic-gate 	 */
4180Sstevel@tonic-gate 	for (i = num; i < count - 1; i++)
4190Sstevel@tonic-gate 		*(work_list.list + i) = *(work_list.list + i + 1);
4200Sstevel@tonic-gate 	/*
4210Sstevel@tonic-gate 	 * If the size of the list in sectors has changed, reallocate
4220Sstevel@tonic-gate 	 * the list to shrink it appropriately.
4230Sstevel@tonic-gate 	 */
424*9889SLarry.Liu@Sun.COM 	if (deflist_size(cur_blksz, count - 1) <
425*9889SLarry.Liu@Sun.COM 	    deflist_size(cur_blksz, count))
4260Sstevel@tonic-gate 		work_list.list = (struct defect_entry *)rezalloc(
427*9889SLarry.Liu@Sun.COM 		    (void *)work_list.list,
428*9889SLarry.Liu@Sun.COM 		    deflist_size(cur_blksz, count - 1) * cur_blksz);
4290Sstevel@tonic-gate 	/*
4300Sstevel@tonic-gate 	 * Decrement the defect count.
4310Sstevel@tonic-gate 	 */
4320Sstevel@tonic-gate 	work_list.header.count--;
4330Sstevel@tonic-gate 	/*
4340Sstevel@tonic-gate 	 * Recalculate the list's checksum.
4350Sstevel@tonic-gate 	 */
4360Sstevel@tonic-gate 	(void) checkdefsum(&work_list, CK_MAKESUM);
4370Sstevel@tonic-gate 	/*
4380Sstevel@tonic-gate 	 * Mark the working list dirty since we modified it.
4390Sstevel@tonic-gate 	 */
4400Sstevel@tonic-gate 	work_list.flags |= LIST_DIRTY;
4410Sstevel@tonic-gate 	fmt_print("defect number %d deleted.\n\n", ++num);
4420Sstevel@tonic-gate 	exit_critical();
4430Sstevel@tonic-gate 	return (0);
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate /*
4470Sstevel@tonic-gate  * This routine implements the 'print' command.  It prints the working
4480Sstevel@tonic-gate  * defect list out in human-readable format.
4490Sstevel@tonic-gate  */
4500Sstevel@tonic-gate int
d_print()4510Sstevel@tonic-gate d_print()
4520Sstevel@tonic-gate {
4530Sstevel@tonic-gate 	int	i, nomore = 0;
4540Sstevel@tonic-gate 	int	c, one_line = 0;
4550Sstevel@tonic-gate 	int	tty_lines = get_tty_lines();
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	/*
4580Sstevel@tonic-gate 	 * If the working list is null, there's nothing to print.
4590Sstevel@tonic-gate 	 */
4600Sstevel@tonic-gate 	if (work_list.list == NULL) {
4610Sstevel@tonic-gate 		if (EMBEDDED_SCSI)
4620Sstevel@tonic-gate 			err_print(
4630Sstevel@tonic-gate "No list defined,extract primary or grown or both defects list first.\n");
4640Sstevel@tonic-gate 		else
4650Sstevel@tonic-gate 			err_print("No working list defined.\n");
4660Sstevel@tonic-gate 		return (-1);
4670Sstevel@tonic-gate 	}
4680Sstevel@tonic-gate 	/*
4690Sstevel@tonic-gate 	 * If we're running from a file, don't use the paging scheme.
4700Sstevel@tonic-gate 	 * If we are running interactive, turn off echoing.
4710Sstevel@tonic-gate 	 */
4720Sstevel@tonic-gate 	if (option_f || (!isatty(0)) || (!isatty(1)))
4730Sstevel@tonic-gate 		nomore++;
4740Sstevel@tonic-gate 	else {
4750Sstevel@tonic-gate 		enter_critical();
4760Sstevel@tonic-gate 		echo_off();
4770Sstevel@tonic-gate 		charmode_on();
4780Sstevel@tonic-gate 		exit_critical();
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 	/* Print out the banner. */
4810Sstevel@tonic-gate 	if (work_list.header.count != 0)
4820Sstevel@tonic-gate 		fmt_print(DEF_PRINTHEADER);
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	/*
4850Sstevel@tonic-gate 	 * Loop through the each defect in the working list.
4860Sstevel@tonic-gate 	 */
4870Sstevel@tonic-gate 	for (i = 0; i < work_list.header.count; i++) {
4880Sstevel@tonic-gate 		/*
4890Sstevel@tonic-gate 		 * If we are paging and hit the end of a page, wait for
4900Sstevel@tonic-gate 		 * the user to hit either space-bar, "q", or return
4910Sstevel@tonic-gate 		 * before going on.
4920Sstevel@tonic-gate 		 */
4930Sstevel@tonic-gate 		if (one_line ||
494*9889SLarry.Liu@Sun.COM 		    (!nomore && ((i + 1) % (tty_lines - 1) == 0))) {
4950Sstevel@tonic-gate 			/*
4960Sstevel@tonic-gate 			 * Get the next character.
4970Sstevel@tonic-gate 			 */
4980Sstevel@tonic-gate 			fmt_print("- hit space for more - ");
4990Sstevel@tonic-gate 			c = getchar();
5000Sstevel@tonic-gate 			fmt_print("\015");
5010Sstevel@tonic-gate 			one_line = 0;
5020Sstevel@tonic-gate 			/* Handle display one line command (return key) */
5030Sstevel@tonic-gate 			if (c == '\012') {
5040Sstevel@tonic-gate 				one_line++;
5050Sstevel@tonic-gate 			}
5060Sstevel@tonic-gate 			/* Handle Quit command */
5070Sstevel@tonic-gate 			if (c == 'q') {
5080Sstevel@tonic-gate 				fmt_print("                       \015");
5090Sstevel@tonic-gate 				goto PRINT_EXIT;
5100Sstevel@tonic-gate 			}
5110Sstevel@tonic-gate 			/* Handle ^D */
5120Sstevel@tonic-gate 			if (c == '\004')
5130Sstevel@tonic-gate 				fullabort();
5140Sstevel@tonic-gate 		}
5150Sstevel@tonic-gate 		/*
5160Sstevel@tonic-gate 		 * Print the defect.
5170Sstevel@tonic-gate 		 */
5180Sstevel@tonic-gate 		pr_defect(work_list.list + i, i);
5190Sstevel@tonic-gate 	}
5200Sstevel@tonic-gate 	fmt_print("total of %d defects.\n\n", i);
5210Sstevel@tonic-gate 	/*
5220Sstevel@tonic-gate 	 * If we were doing paging, turn echoing back on.
5230Sstevel@tonic-gate 	 */
5240Sstevel@tonic-gate PRINT_EXIT:
5250Sstevel@tonic-gate 	if (!nomore) {
5260Sstevel@tonic-gate 		enter_critical();
5270Sstevel@tonic-gate 		charmode_off();
5280Sstevel@tonic-gate 		echo_on();
5290Sstevel@tonic-gate 		exit_critical();
5300Sstevel@tonic-gate 	}
5310Sstevel@tonic-gate 	return (0);
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate /*
5350Sstevel@tonic-gate  * This routine implements the 'dump' command.  It writes the working
5360Sstevel@tonic-gate  * defect list to a file.
5370Sstevel@tonic-gate  */
5380Sstevel@tonic-gate int
d_dump()5390Sstevel@tonic-gate d_dump()
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate 	int	i, status = 0;
5420Sstevel@tonic-gate 	char	*str;
5430Sstevel@tonic-gate 	FILE	*fptr;
5440Sstevel@tonic-gate 	struct	defect_entry *dptr;
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	/*
5470Sstevel@tonic-gate 	 * If the working list is null, there's nothing to do.
5480Sstevel@tonic-gate 	 */
5490Sstevel@tonic-gate 	if (work_list.list == NULL) {
5500Sstevel@tonic-gate 		if (EMBEDDED_SCSI)
5510Sstevel@tonic-gate 			err_print(
5520Sstevel@tonic-gate "No list defined,extract primary or grown or both defects list first.\n");
5530Sstevel@tonic-gate 		else
5540Sstevel@tonic-gate 			err_print("No working list defined.\n");
5550Sstevel@tonic-gate 		return (-1);
5560Sstevel@tonic-gate 	}
5570Sstevel@tonic-gate 	/*
5580Sstevel@tonic-gate 	 * Ask the user for the name of the defect file.  Note that the
5590Sstevel@tonic-gate 	 * input will be in malloc'd space since we are inputting
5600Sstevel@tonic-gate 	 * type OSTR.
5610Sstevel@tonic-gate 	 */
562362Sbg159949 	str = (char *)(uintptr_t)input(FIO_OSTR, "Enter name of defect file",
563362Sbg159949 	    ':', (u_ioparam_t *)NULL, (int *)NULL, DATA_INPUT);
5640Sstevel@tonic-gate 	/*
5650Sstevel@tonic-gate 	 * Lock out interrupts so the file doesn't get half written.
5660Sstevel@tonic-gate 	 */
5670Sstevel@tonic-gate 	enter_critical();
5680Sstevel@tonic-gate 	/*
5690Sstevel@tonic-gate 	 * Open the file for writing.
5700Sstevel@tonic-gate 	 */
5710Sstevel@tonic-gate 	if ((fptr = fopen(str, "w+")) == NULL) {
5720Sstevel@tonic-gate 		err_print("unable to open defect file.\n");
5730Sstevel@tonic-gate 		status = -1;
5740Sstevel@tonic-gate 		goto out;
5750Sstevel@tonic-gate 	}
5760Sstevel@tonic-gate 	/*
5770Sstevel@tonic-gate 	 * Print a header containing the magic number, count, and checksum.
5780Sstevel@tonic-gate 	 */
5790Sstevel@tonic-gate 	(void) fprintf(fptr, "0x%08x%8d  0x%08x\n",
580*9889SLarry.Liu@Sun.COM 	    work_list.header.magicno,
581*9889SLarry.Liu@Sun.COM 	    work_list.header.count, work_list.header.cksum);
5820Sstevel@tonic-gate 	/*
5830Sstevel@tonic-gate 	 * Loop through each defect in the working list.  Write the
5840Sstevel@tonic-gate 	 * defect info to the defect file.
5850Sstevel@tonic-gate 	 */
5860Sstevel@tonic-gate 	for (i = 0; i < work_list.header.count; i++) {
5870Sstevel@tonic-gate 		dptr = work_list.list + i;
5880Sstevel@tonic-gate 		(void) fprintf(fptr, "%4d%8d%7d%8d%8d%8d\n",
589*9889SLarry.Liu@Sun.COM 		    i+1, dptr->cyl, dptr->head,
590*9889SLarry.Liu@Sun.COM 		    dptr->bfi, dptr->nbits, dptr->sect);
5910Sstevel@tonic-gate 	}
5920Sstevel@tonic-gate 	fmt_print("defect file updated, total of %d defects.\n", i);
5930Sstevel@tonic-gate 	/*
5940Sstevel@tonic-gate 	 * Close the defect file.
5950Sstevel@tonic-gate 	 */
5960Sstevel@tonic-gate 	(void) fclose(fptr);
5970Sstevel@tonic-gate out:
5980Sstevel@tonic-gate 	/*
5990Sstevel@tonic-gate 	 * Destroy the string used for the file name.
6000Sstevel@tonic-gate 	 */
6010Sstevel@tonic-gate 	destroy_data(str);
6020Sstevel@tonic-gate 	exit_critical();
6030Sstevel@tonic-gate 	fmt_print("\n");
6040Sstevel@tonic-gate 	return (status);
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate /*
6080Sstevel@tonic-gate  * This routine implements the 'load' command.  It reads the working
6090Sstevel@tonic-gate  * list in from a file.
6100Sstevel@tonic-gate  */
6110Sstevel@tonic-gate int
d_load()6120Sstevel@tonic-gate d_load()
6130Sstevel@tonic-gate {
6140Sstevel@tonic-gate 	int	i, items, status = 0, count, cksum;
6150Sstevel@tonic-gate 	uint_t	magicno;
6160Sstevel@tonic-gate 	char	*str;
6170Sstevel@tonic-gate 	TOKEN	filename;
6180Sstevel@tonic-gate 	FILE	*fptr;
6190Sstevel@tonic-gate 	struct	defect_entry *dptr;
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	assert(!EMBEDDED_SCSI);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	/*
6240Sstevel@tonic-gate 	 * Ask the user for the name of the defect file.  Note that the
6250Sstevel@tonic-gate 	 * input will be malloc'd space since we inputted type OSTR.
6260Sstevel@tonic-gate 	 */
627362Sbg159949 	str = (char *)(uintptr_t)input(FIO_OSTR, "Enter name of defect file",
628362Sbg159949 	    ':', (u_ioparam_t *)NULL, (int *)NULL, DATA_INPUT);
6290Sstevel@tonic-gate 	/*
6300Sstevel@tonic-gate 	 * Copy the file name into local space then destroy the string
6310Sstevel@tonic-gate 	 * it came in.  This is simply a precaution against later having
6320Sstevel@tonic-gate 	 * to remember to destroy this space.
6330Sstevel@tonic-gate 	 */
6340Sstevel@tonic-gate 	enter_critical();
6350Sstevel@tonic-gate 	(void) strcpy(filename, str);
6360Sstevel@tonic-gate 	destroy_data(str);
6370Sstevel@tonic-gate 	exit_critical();
6380Sstevel@tonic-gate 	/*
6390Sstevel@tonic-gate 	 * See if the defect file is accessable.  If not, we can't load
6400Sstevel@tonic-gate 	 * from it.  We do this here just so we can get out before asking
6410Sstevel@tonic-gate 	 * the user for confirmation.
6420Sstevel@tonic-gate 	 */
6430Sstevel@tonic-gate 	status = access(filename, 4);
6440Sstevel@tonic-gate 	if (status) {
6450Sstevel@tonic-gate 		err_print("defect file not accessable.\n");
6460Sstevel@tonic-gate 		return (-1);
6470Sstevel@tonic-gate 	}
6480Sstevel@tonic-gate 	/*
6490Sstevel@tonic-gate 	 * Make sure the user is serious.
6500Sstevel@tonic-gate 	 */
6510Sstevel@tonic-gate 	if (check("ready to update working list, continue"))
6520Sstevel@tonic-gate 		return (-1);
6530Sstevel@tonic-gate 	/*
6540Sstevel@tonic-gate 	 * Lock out interrupts so the list doesn't get half loaded.
6550Sstevel@tonic-gate 	 */
6560Sstevel@tonic-gate 	enter_critical();
6570Sstevel@tonic-gate 	/*
6580Sstevel@tonic-gate 	 * Open the defect file.
6590Sstevel@tonic-gate 	 */
6600Sstevel@tonic-gate 	if ((fptr = fopen(filename, "r")) == NULL) {
6610Sstevel@tonic-gate 		err_print("unable to open defect file.\n");
6620Sstevel@tonic-gate 		exit_critical();
6630Sstevel@tonic-gate 		return (-1);
6640Sstevel@tonic-gate 	}
6650Sstevel@tonic-gate 	/*
6660Sstevel@tonic-gate 	 * Scan in the header.
6670Sstevel@tonic-gate 	 */
6680Sstevel@tonic-gate 	items = fscanf(fptr, "0x%x%d  0x%x\n", &magicno,
669*9889SLarry.Liu@Sun.COM 	    &count, (uint_t *)&cksum);
6700Sstevel@tonic-gate 	/*
6710Sstevel@tonic-gate 	 * If the header is wrong, this isn't a good defect file.
6720Sstevel@tonic-gate 	 */
6730Sstevel@tonic-gate 	if (items != 3 || count < 0 ||
6740Sstevel@tonic-gate 	    (magicno != (uint_t)DEFECT_MAGIC &&
675*9889SLarry.Liu@Sun.COM 	    magicno != (uint_t)NO_CHECKSUM)) {
6760Sstevel@tonic-gate 		err_print("Defect file is corrupted.\n");
6770Sstevel@tonic-gate 		status = -1;
6780Sstevel@tonic-gate 		goto out;
6790Sstevel@tonic-gate 	}
6800Sstevel@tonic-gate 	/*
6810Sstevel@tonic-gate 	 * Kill off any old defects in the working list.
6820Sstevel@tonic-gate 	 */
6830Sstevel@tonic-gate 	kill_deflist(&work_list);
6840Sstevel@tonic-gate 	/*
6850Sstevel@tonic-gate 	 * Load the working list header with the header info.
6860Sstevel@tonic-gate 	 */
6870Sstevel@tonic-gate 	if (magicno == NO_CHECKSUM)
6880Sstevel@tonic-gate 		work_list.header.magicno = (uint_t)DEFECT_MAGIC;
6890Sstevel@tonic-gate 	else
6900Sstevel@tonic-gate 		work_list.header.magicno = magicno;
6910Sstevel@tonic-gate 	work_list.header.count = count;
6920Sstevel@tonic-gate 	work_list.header.cksum = cksum;
6930Sstevel@tonic-gate 	/*
6940Sstevel@tonic-gate 	 * Allocate space for the new list.
6950Sstevel@tonic-gate 	 */
696*9889SLarry.Liu@Sun.COM 	work_list.list = (struct defect_entry *)zalloc(
697*9889SLarry.Liu@Sun.COM 	    deflist_size(cur_blksz, count) * cur_blksz);
6980Sstevel@tonic-gate 	/*
6990Sstevel@tonic-gate 	 * Mark the working list dirty since we are modifying it.
7000Sstevel@tonic-gate 	 */
7010Sstevel@tonic-gate 	work_list.flags |= LIST_DIRTY;
7020Sstevel@tonic-gate 	/*
7030Sstevel@tonic-gate 	 * Loop through each defect in the defect file.
7040Sstevel@tonic-gate 	 */
7050Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
7060Sstevel@tonic-gate 		dptr = work_list.list + i;
7070Sstevel@tonic-gate 		/*
7080Sstevel@tonic-gate 		 * Scan the info into the defect entry.
7090Sstevel@tonic-gate 		 */
7100Sstevel@tonic-gate 		items = fscanf(fptr, "%*d%hd%hd%d%hd%hd\n", &dptr->cyl,
7110Sstevel@tonic-gate 		    &dptr->head, &dptr->bfi, &dptr->nbits, &dptr->sect);
7120Sstevel@tonic-gate 		/*
7130Sstevel@tonic-gate 		 * If it didn't scan right, give up.
7140Sstevel@tonic-gate 		 */
7150Sstevel@tonic-gate 		if (items != 5)
7160Sstevel@tonic-gate 			goto bad;
7170Sstevel@tonic-gate 	}
7180Sstevel@tonic-gate 	/*
7190Sstevel@tonic-gate 	 * Check to be sure the checksum from the defect file was correct
7200Sstevel@tonic-gate 	 * unless there wasn't supposed to be a checksum.
7210Sstevel@tonic-gate 	 * If there was supposed to be a valid checksum and there isn't
7220Sstevel@tonic-gate 	 * then give up.
7230Sstevel@tonic-gate 	 */
7240Sstevel@tonic-gate 	if (magicno != NO_CHECKSUM && checkdefsum(&work_list, CK_CHECKSUM))
7250Sstevel@tonic-gate 		goto bad;
7260Sstevel@tonic-gate 	fmt_print("working list updated, total of %d defects.\n", i);
7270Sstevel@tonic-gate 	goto out;
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate bad:
7300Sstevel@tonic-gate 	/*
7310Sstevel@tonic-gate 	 * Some kind of error occurred.  Kill off the working list and
7320Sstevel@tonic-gate 	 * mark the status bad.
7330Sstevel@tonic-gate 	 */
7340Sstevel@tonic-gate 	err_print("Defect file is corrupted, working list set to NULL.\n");
7350Sstevel@tonic-gate 	kill_deflist(&work_list);
7360Sstevel@tonic-gate 	status = -1;
7370Sstevel@tonic-gate out:
7380Sstevel@tonic-gate 	/*
7390Sstevel@tonic-gate 	 * Close the defect file.
7400Sstevel@tonic-gate 	 */
7410Sstevel@tonic-gate 	(void) fclose(fptr);
7420Sstevel@tonic-gate 	exit_critical();
7430Sstevel@tonic-gate 	fmt_print("\n");
7440Sstevel@tonic-gate 	return (status);
7450Sstevel@tonic-gate }
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate /*
7480Sstevel@tonic-gate  * This routine implements the 'commit' command.  It causes the current
7490Sstevel@tonic-gate  * defect list to be set equal to the working defect list.  It is the only
7500Sstevel@tonic-gate  * way that changes made to the working list can actually take effect in
7510Sstevel@tonic-gate  * the next format.
7520Sstevel@tonic-gate  */
7530Sstevel@tonic-gate int
d_commit()7540Sstevel@tonic-gate d_commit()
7550Sstevel@tonic-gate {
7560Sstevel@tonic-gate 	/*
7570Sstevel@tonic-gate 	 * If the working list wasn't modified, no commit is necessary.
7580Sstevel@tonic-gate 	 */
7590Sstevel@tonic-gate 	if (work_list.list != NULL && !(work_list.flags & LIST_DIRTY)) {
7600Sstevel@tonic-gate 		err_print("working list was not modified.\n");
7610Sstevel@tonic-gate 		return (0);
7620Sstevel@tonic-gate 	}
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 	/*
7650Sstevel@tonic-gate 	 * Make sure the user is serious.
7660Sstevel@tonic-gate 	 */
7670Sstevel@tonic-gate 	if (check("Ready to update Current Defect List, continue"))
7680Sstevel@tonic-gate 		return (-1);
7690Sstevel@tonic-gate 	return (do_commit());
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate int
do_commit()7730Sstevel@tonic-gate do_commit()
7740Sstevel@tonic-gate {
7750Sstevel@tonic-gate 	int	status;
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	if ((status = commit_list()) == 0) {
7780Sstevel@tonic-gate 		/*
7790Sstevel@tonic-gate 		 * Remind the user to format the drive, since changing
7800Sstevel@tonic-gate 		 * the list does nothing unless a format is performed.
7810Sstevel@tonic-gate 		 */
7820Sstevel@tonic-gate 		fmt_print(\
7830Sstevel@tonic-gate "Disk must be reformatted for changes to take effect.\n\n");
7840Sstevel@tonic-gate 	}
7850Sstevel@tonic-gate 	return (status);
7860Sstevel@tonic-gate }
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate static int
commit_list()7900Sstevel@tonic-gate commit_list()
7910Sstevel@tonic-gate {
7920Sstevel@tonic-gate 	int	i;
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	/*
7950Sstevel@tonic-gate 	 * Lock out interrupts so the list doesn't get half copied.
7960Sstevel@tonic-gate 	 */
7970Sstevel@tonic-gate 	enter_critical();
7980Sstevel@tonic-gate 	/*
7990Sstevel@tonic-gate 	 * Kill off any current defect list.
8000Sstevel@tonic-gate 	 */
8010Sstevel@tonic-gate 	kill_deflist(&cur_list);
8020Sstevel@tonic-gate 	/*
8030Sstevel@tonic-gate 	 * If the working list is null, initialize it to zero length.
8040Sstevel@tonic-gate 	 * This is so the user can do a commit on a null list and get
8050Sstevel@tonic-gate 	 * a zero length list.  Otherwise there would be no way to get
8060Sstevel@tonic-gate 	 * a zero length list conveniently.
8070Sstevel@tonic-gate 	 */
8080Sstevel@tonic-gate 	if (work_list.list == NULL) {
8090Sstevel@tonic-gate 		work_list.header.magicno = (uint_t)DEFECT_MAGIC;
8100Sstevel@tonic-gate 		work_list.header.count = 0;
8110Sstevel@tonic-gate 		work_list.list = (struct defect_entry *)zalloc(
812*9889SLarry.Liu@Sun.COM 		    deflist_size(cur_blksz, 0) * cur_blksz);
8130Sstevel@tonic-gate 	}
8140Sstevel@tonic-gate 	/*
8150Sstevel@tonic-gate 	 * Copy the working list into the current list.
8160Sstevel@tonic-gate 	 */
8170Sstevel@tonic-gate 	cur_list.header = work_list.header;
8180Sstevel@tonic-gate 	cur_list.list = (struct defect_entry *)zalloc(
819*9889SLarry.Liu@Sun.COM 	    deflist_size(cur_blksz, cur_list.header.count) * cur_blksz);
8200Sstevel@tonic-gate 	for (i = 0; i < cur_list.header.count; i++)
8210Sstevel@tonic-gate 		*(cur_list.list + i) = *(work_list.list + i);
8220Sstevel@tonic-gate 	/*
8230Sstevel@tonic-gate 	 * Mark the working list clean, since it is now the same as the
8240Sstevel@tonic-gate 	 * current list.  Note we do not mark the current list dirty,
8250Sstevel@tonic-gate 	 * even though it has been changed.  This is because it does
8260Sstevel@tonic-gate 	 * not reflect the state of disk, so we don't want it written
8270Sstevel@tonic-gate 	 * out until a format has been done.  The format will mark it
8280Sstevel@tonic-gate 	 * dirty and write it out.
8290Sstevel@tonic-gate 	 */
8300Sstevel@tonic-gate 	work_list.flags &= ~(LIST_DIRTY|LIST_RELOAD);
8310Sstevel@tonic-gate 	cur_list.flags = work_list.flags;
8320Sstevel@tonic-gate 	if (EMBEDDED_SCSI)
8330Sstevel@tonic-gate 		fmt_print("Defect List has a total of %d defects.\n",
8340Sstevel@tonic-gate 		    cur_list.header.count);
8350Sstevel@tonic-gate 	else
8360Sstevel@tonic-gate 		fmt_print("Current Defect List updated, total of %d defects.\n",
8370Sstevel@tonic-gate 		    cur_list.header.count);
8380Sstevel@tonic-gate 	exit_critical();
8390Sstevel@tonic-gate 	return (0);
8400Sstevel@tonic-gate }
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate /*
8440Sstevel@tonic-gate  * This routine implements the 'create' command.  It creates the
8450Sstevel@tonic-gate  * manufacturer's defect on the current disk from the defect list
8460Sstevel@tonic-gate  */
8470Sstevel@tonic-gate int
d_create()8480Sstevel@tonic-gate d_create()
8490Sstevel@tonic-gate {
8500Sstevel@tonic-gate 	int	status;
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	assert(!EMBEDDED_SCSI);
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	/*
8550Sstevel@tonic-gate 	 * If the controller does not support the extraction, we're out
8560Sstevel@tonic-gate 	 * of luck.
8570Sstevel@tonic-gate 	 */
8580Sstevel@tonic-gate 	if (cur_ops->op_create == NULL) {
8590Sstevel@tonic-gate 		err_print("Controller does not support creating ");
8600Sstevel@tonic-gate 		err_print("manufacturer's defect list.\n");
8610Sstevel@tonic-gate 		return (-1);
8620Sstevel@tonic-gate 	}
8630Sstevel@tonic-gate 	/*
8640Sstevel@tonic-gate 	 * Make sure the user is serious.  Note, for SCSI disks
8650Sstevel@tonic-gate 	 * since this is instantaneous, we will just do it and
8660Sstevel@tonic-gate 	 * not ask for confirmation.
8670Sstevel@tonic-gate 	 */
8680Sstevel@tonic-gate 	if (! (cur_ctype->ctype_flags & CF_SCSI) &&
8690Sstevel@tonic-gate 	    check(
8700Sstevel@tonic-gate "Ready to create the manufacturers defect information on the disk.\n\
8710Sstevel@tonic-gate This cannot be interrupted and may take a long while.\n\
8720Sstevel@tonic-gate IT WILL DESTROY ALL OF THE DATA ON THE DISK! Continue"))
8730Sstevel@tonic-gate 		return (-1);
8740Sstevel@tonic-gate 	/*
8750Sstevel@tonic-gate 	 * Lock out interrupts so we don't get half the list.
8760Sstevel@tonic-gate 	 */
8770Sstevel@tonic-gate 	enter_critical();
8780Sstevel@tonic-gate 	fmt_print("Creating manufacturer's defect list...");
8790Sstevel@tonic-gate 	/*
8800Sstevel@tonic-gate 	 * Do the Creation
8810Sstevel@tonic-gate 	 */
8820Sstevel@tonic-gate 	status = (*cur_ops->op_create)(&work_list);
8830Sstevel@tonic-gate 	if (status) {
8840Sstevel@tonic-gate 		fmt_print("Creation failed.\n\n");
8850Sstevel@tonic-gate 	} else {
8860Sstevel@tonic-gate 		fmt_print("Creation complete.\n");
8870Sstevel@tonic-gate 	}
8880Sstevel@tonic-gate 	exit_critical();
8890Sstevel@tonic-gate 	/*
8900Sstevel@tonic-gate 	 * Return status.
8910Sstevel@tonic-gate 	 */
8920Sstevel@tonic-gate 	return (status);
8930Sstevel@tonic-gate }
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate /*
8970Sstevel@tonic-gate  * Extract primary defect list - SCSI only
8980Sstevel@tonic-gate  */
8990Sstevel@tonic-gate int
d_primary()9000Sstevel@tonic-gate d_primary()
9010Sstevel@tonic-gate {
9020Sstevel@tonic-gate 	int	status;
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	assert(EMBEDDED_SCSI);
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	/*
9070Sstevel@tonic-gate 	 * Lock out interrupts so we don't get half the list and
9080Sstevel@tonic-gate 	 * Kill off the working list.
9090Sstevel@tonic-gate 	 */
9100Sstevel@tonic-gate 	enter_critical();
9110Sstevel@tonic-gate 	kill_deflist(&work_list);
9120Sstevel@tonic-gate 	fmt_print("Extracting primary defect list...");
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	/*
9150Sstevel@tonic-gate 	 * Do the extraction.
9160Sstevel@tonic-gate 	 */
9170Sstevel@tonic-gate 	status = scsi_ex_man(&work_list);
9180Sstevel@tonic-gate 	if (status) {
9190Sstevel@tonic-gate 		fmt_print("Extraction failed.\n\n");
9200Sstevel@tonic-gate 	} else {
9210Sstevel@tonic-gate 		fmt_print("Extraction complete.\n");
9220Sstevel@tonic-gate 		/*
9230Sstevel@tonic-gate 		 * Mark the working list dirty since we modified it.
9240Sstevel@tonic-gate 		 * Automatically commit it, for SCSI only.
9250Sstevel@tonic-gate 		 */
9260Sstevel@tonic-gate 		work_list.flags |= LIST_DIRTY;
9270Sstevel@tonic-gate 		status = commit_list();
9280Sstevel@tonic-gate 		fmt_print("\n");
9290Sstevel@tonic-gate 	}
9300Sstevel@tonic-gate 	exit_critical();
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	/*
9330Sstevel@tonic-gate 	 * Return status.
9340Sstevel@tonic-gate 	 */
9350Sstevel@tonic-gate 	return (status);
9360Sstevel@tonic-gate }
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate /*
9400Sstevel@tonic-gate  * Extract grown defects list - SCSI only
9410Sstevel@tonic-gate  */
9420Sstevel@tonic-gate int
d_grown()9430Sstevel@tonic-gate d_grown()
9440Sstevel@tonic-gate {
9450Sstevel@tonic-gate 	int	status;
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	assert(EMBEDDED_SCSI);
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	/*
9500Sstevel@tonic-gate 	 * Lock out interrupts so we don't get half the list and
9510Sstevel@tonic-gate 	 * Kill off the working list.
9520Sstevel@tonic-gate 	 */
9530Sstevel@tonic-gate 	enter_critical();
9540Sstevel@tonic-gate 	kill_deflist(&work_list);
9550Sstevel@tonic-gate 	fmt_print("Extracting grown defects list...");
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	/*
9580Sstevel@tonic-gate 	 * Do the extraction.
9590Sstevel@tonic-gate 	 */
9600Sstevel@tonic-gate 	status = scsi_ex_grown(&work_list);
9610Sstevel@tonic-gate 	if (status) {
9620Sstevel@tonic-gate 		fmt_print("Extraction failed.\n\n");
9630Sstevel@tonic-gate 	} else {
9640Sstevel@tonic-gate 		fmt_print("Extraction complete.\n");
9650Sstevel@tonic-gate 		/*
9660Sstevel@tonic-gate 		 * Mark the working list dirty since we modified it.
9670Sstevel@tonic-gate 		 * Automatically commit it, for SCSI only.
9680Sstevel@tonic-gate 		 */
9690Sstevel@tonic-gate 		work_list.flags |= LIST_DIRTY;
9700Sstevel@tonic-gate 		status = commit_list();
9710Sstevel@tonic-gate 		fmt_print("\n");
9720Sstevel@tonic-gate 	}
9730Sstevel@tonic-gate 	exit_critical();
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	/*
9760Sstevel@tonic-gate 	 * Return status.
9770Sstevel@tonic-gate 	 */
9780Sstevel@tonic-gate 	return (status);
9790Sstevel@tonic-gate }
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate /*
9830Sstevel@tonic-gate  * Extract both primary and grown defects list - SCSI only
9840Sstevel@tonic-gate  */
9850Sstevel@tonic-gate int
d_both()9860Sstevel@tonic-gate d_both()
9870Sstevel@tonic-gate {
9880Sstevel@tonic-gate 	int	status;
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 	assert(EMBEDDED_SCSI);
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	/*
9930Sstevel@tonic-gate 	 * Lock out interrupts so we don't get half the list and
9940Sstevel@tonic-gate 	 * Kill off the working list.
9950Sstevel@tonic-gate 	 */
9960Sstevel@tonic-gate 	enter_critical();
9970Sstevel@tonic-gate 	kill_deflist(&work_list);
9980Sstevel@tonic-gate 	fmt_print("Extracting both primary and grown defects lists...");
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 	/*
10010Sstevel@tonic-gate 	 * Do the extraction.
10020Sstevel@tonic-gate 	 */
10030Sstevel@tonic-gate 	status = scsi_ex_cur(&work_list);
10040Sstevel@tonic-gate 	if (status) {
10050Sstevel@tonic-gate 		fmt_print("Extraction failed.\n\n");
10060Sstevel@tonic-gate 	} else {
10070Sstevel@tonic-gate 		fmt_print("Extraction complete.\n");
10080Sstevel@tonic-gate 		/*
10090Sstevel@tonic-gate 		 * Mark the working list dirty since we modified it.
10100Sstevel@tonic-gate 		 * Automatically commit it, for SCSI only.
10110Sstevel@tonic-gate 		 */
10120Sstevel@tonic-gate 		work_list.flags |= LIST_DIRTY;
10130Sstevel@tonic-gate 		status = commit_list();
10140Sstevel@tonic-gate 		fmt_print("\n");
10150Sstevel@tonic-gate 	}
10160Sstevel@tonic-gate 	exit_critical();
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	/*
10190Sstevel@tonic-gate 	 * Return status.
10200Sstevel@tonic-gate 	 */
10210Sstevel@tonic-gate 	return (status);
10220Sstevel@tonic-gate }
1023