xref: /illumos-gate/usr/src/cmd/addbadsec/addbadsec.c (revision d362b749)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1990, 1991 UNIX System Laboratories, Inc.	*/
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 /*
32  * Copyrighted as an unpublished work.
33  * (c) Copyright INTERACTIVE Systems Corporation 1986, 1988, 1990
34  * All rights reserved.
35  */
36 
37 #pragma ident	"%Z%%M%	%I%	%E% SMI"
38 
39 #include <stdio.h>
40 #include <fcntl.h>
41 #include <memory.h>
42 #include <sys/types.h>
43 #include <sys/param.h>
44 #include <sys/stat.h>
45 #include <sys/mkdev.h>
46 #include <sys/vtoc.h>
47 #include <sys/dkio.h>
48 #include <errno.h>
49 #include <sys/scsi/generic/commands.h>
50 #include <sys/scsi/impl/commands.h>
51 #include <sys/scsi/impl/uscsi.h>
52 #include "badsec.h"
53 
54 char    *devname;		/* name of device */
55 int	devfd;			/* device file descriptor */
56 struct  dk_geom      	dkg;	/* geometry */
57 struct  vtoc	vtoc;		/* table of contents */
58 char	*progname;
59 
60 extern	struct	badsec_lst *badsl_chain;
61 extern	int	badsl_chain_cnt;
62 extern	struct	badsec_lst *gbadsl_chain;
63 extern	int	gbadsl_chain_cnt;
64 
65 int		alts_fd;
66 
67 static void giveusage(void);
68 static void rd_gbad(FILE *badsecfd);
69 static void add_gbad(int badsec_entry);
70 
71 int
72 main(int argc, char *argv[])
73 {
74 	extern int	optind;
75 	extern char	*optarg;
76 
77 	static char     options[] = "Ipa:f:";
78 	char		numbuf[100];
79 	char		*nxtarg;
80 	char		*alts_name;
81 	minor_t 	minor_val;
82 	struct stat 	statbuf;
83 	struct partition	*part = NULL;
84 	int		alts_slice = -1;
85 	int		l;
86 	int		p;
87 	int		init_flag = 0;
88 	int		print_flag = 0;
89 	int 		c;
90 	int 		i;
91 	FILE		*badsecfd = NULL;
92 	struct badsec_lst *blc_p;
93 
94 	progname = argv[0];
95 	while ( (c=getopt(argc, argv, options)) != EOF ) {
96 		switch (c) {
97 		case 'I':
98 			init_flag = 1;
99 			break;
100 		case 'p':
101 			print_flag = 1;
102 			break;
103 		case 'a':
104 			nxtarg = optarg;
105 			for (;*nxtarg != '\0';)
106 				add_gbad(strtol(nxtarg, &nxtarg, 0));
107 			break;
108 		case 'f':
109 			if ((badsecfd = fopen(optarg, "r")) == NULL) {
110 				fprintf(stderr, "%s: unable to open %s file\n", progname, optarg);
111 				exit(1);
112 			}
113 			break;
114 		default:
115 			giveusage();
116 			exit(2);
117 		}
118 	}
119 
120 		/* get the last argument -- device stanza */
121 	if (argc != optind+1) {
122 		fprintf(stderr, "Missing disk device name\n");
123 		giveusage();
124 		exit(3);
125 	}
126 	devname = argv[optind];
127 
128 	if (stat(devname, &statbuf)) {
129 		fprintf(stderr, "%s: invalid device %s, stat failed\n", progname, devname);
130 		giveusage();
131 		exit(4);
132 	}
133 	if ((statbuf.st_mode & S_IFMT) != S_IFCHR) {
134 		fprintf(stderr, "%s: device %s is not character special\n", progname, devname);
135 		giveusage();
136 		exit(5);
137 	}
138 	minor_val = minor(statbuf.st_rdev);
139 	/*
140 	 * NEED A DEFINE FOR THE PHYSICAL BIT (0x10)
141 	 */
142 	if ((minor_val & 0x10) == 0) {
143 		fprintf(stderr, "%s: device %s is not a physical slice\n", progname, devname);
144 		giveusage();
145 		exit(6);
146 	}
147 	if ((minor_val % V_NUMPAR) != 0) {
148 		fprintf(stderr, "%s: device %s is not a slice 0 device\n", progname, devname);
149 		giveusage();
150 		exit(7);
151 	}
152 	if ((devfd=open(devname, O_RDWR)) == -1) {
153 		fprintf(stderr, "%s: open of %s failed\n", progname ,devname);
154 		perror("");
155 		exit(8);
156 	}
157 	if ((ioctl (devfd, DKIOCGGEOM, &dkg)) == -1) {
158 		fprintf(stderr, "%s: unable to get disk geometry.\n", progname);
159 		perror("");
160 		exit(9);
161 	}
162 
163 	if (ioctl(devfd, DKIOCGVTOC, &vtoc) == -1)
164 	{
165 		fprintf(stderr, "%s: could not get VTOC.\n", progname);
166 		giveusage();
167 		exit(14);
168 	}
169 
170 	if ((vtoc.v_sanity != VTOC_SANE) || (vtoc.v_version != V_VERSION)) {
171 		fprintf(stderr, "%s: invalid VTOC found.\n", progname);
172 		giveusage();
173 		exit(15);
174 	}
175 	if (badsecfd)
176 		rd_gbad(badsecfd);
177 
178 #ifdef ADDBAD_DEBUG
179 	printf("\n main: Total bad sectors found= %d\n", gbadsl_chain_cnt);
180 	for (blc_p=gbadsl_chain; blc_p; blc_p=blc_p->bl_nxt) {
181 		for (i=0; i<blc_p->bl_cnt; i++)
182 			printf(" badsec=%d ", blc_p->bl_sec[i]);
183 	}
184 	printf("\n");
185 #endif
186 #ifdef PPP
187 	/*
188 	 * If init_flag is set, run to completion.
189 	 */
190 	if (gbadsl_chain_cnt == 0 && init_flag == 0)
191 		/*
192 		 * No defects and not initializing
193 		 */
194 		exit (0);
195 #endif
196 	if (gbadsl_chain_cnt != 0)
197 	{
198 		if (try_hw_remap () == SUCCESS)
199 			exit (0);
200 	}
201 	/*
202 	 * get ALTS slice
203 	 */
204 	for (i = 0; i < V_NUMPAR && alts_slice == -1; i++)
205 	{
206 		if (vtoc.v_part[i].p_tag == V_ALTSCTR)
207 		{
208 			alts_slice = i;
209 			part = &vtoc.v_part[i];
210 		}
211 	}
212 	if (alts_slice == -1)
213 	{
214 		fprintf(stderr, "%s: No alternates slice.\n", progname);
215 		exit(16);
216 	}
217 	l = strlen (devname);
218 	sprintf (numbuf, "%d", alts_slice);
219 	p = strlen (numbuf);
220 	alts_name = (char *)malloc (l + p);
221 	strcpy (alts_name, devname);
222 	alts_name[l - 2] = 's';
223 	strcpy (&alts_name[l - 1], numbuf);
224 	alts_name[l + p - 1] = '\0';
225 	if ((alts_fd=open(alts_name, O_RDWR)) == -1) {
226 		fprintf(stderr, "%s: open of %s failed\n", progname ,alts_name);
227 		perror("");
228 		exit(9);
229 	}
230 	if (print_flag)
231 	{
232 		print_altsec (part);
233 		exit (0);
234 	}
235 	updatebadsec(part, init_flag);
236 	wr_altsctr();
237 
238 	if (ioctl(devfd, DKIOCADDBAD, NULL) == -1) {
239 		fprintf(stderr,  "Warning: DKIOCADDBAD io control failed. System must be re-booted\n");
240 		fprintf(stderr, "for alternate sectors to be usable.\n");
241 		exit(17);
242 	}
243 	sync();
244 
245 	fclose(badsecfd);
246 	close (alts_fd);
247 	close (devfd);
248 	return(0);
249 }
250 
251 /*
252  * Giveusage ()
253  * Give a (not so) concise message on how to use this program.
254  */
255 static
256 void giveusage(void)
257 {
258 	fprintf(stderr, "%s [-p] [-a sector] [-f filename] raw-device\n", progname);
259 	fprintf(stderr, "	p - Print existing bad block map\n");
260 	fprintf(stderr, "	a - Add the given sectors to the bad block list\n");
261 	fprintf(stderr, "	f - Add the sectors from <filename> to the bad block list\n");
262 	if (devfd)
263 		close(devfd);
264 }
265 
266 
267 /*
268  *	read in the additional growing bad sectors
269  */
270 static void
271 rd_gbad(FILE *badsecfd)
272 {
273 	int	badsec_entry;
274 	int	status;
275 
276 	status = fscanf(badsecfd, "%d", &badsec_entry);
277 	while (status!=EOF) {
278 		add_gbad(badsec_entry);
279 		status = fscanf(badsecfd, "%d", &badsec_entry);
280 	}
281 }
282 
283 static void
284 add_gbad(int badsec_entry)
285 {
286 	struct badsec_lst *blc_p;
287 
288 	if (!gbadsl_chain) {
289 		blc_p = (struct badsec_lst *)malloc(BADSLSZ);
290 		if (!blc_p) {
291 			fprintf(stderr, "Unable to allocate memory for additional bad sectors\n");
292 			exit(18);
293 		}
294 		gbadsl_chain = blc_p;
295 		blc_p->bl_cnt = 0;
296 		blc_p->bl_nxt = 0;
297 	}
298 	for (blc_p = gbadsl_chain; blc_p->bl_nxt; )
299 		blc_p = blc_p->bl_nxt;
300 
301 	if (blc_p->bl_cnt == MAXBLENT) {
302 		blc_p->bl_nxt = (struct badsec_lst *)malloc(BADSLSZ);
303 		if (!blc_p->bl_nxt) {
304 			fprintf(stderr, "Unable to allocate memory for additional bad sectors\n");
305 			exit(19);
306 		}
307 		blc_p = blc_p->bl_nxt;
308 		blc_p->bl_cnt = 0;
309 		blc_p->bl_nxt = 0;
310 	}
311 	blc_p->bl_sec[blc_p->bl_cnt++] = badsec_entry;
312 	gbadsl_chain_cnt++;
313 }
314 
315 /*
316  * Map a block using hardware (SCSI) techniques.
317  */
318 /*ARGSUSED*/
319 int
320 hardware_remap (bn)
321 int	bn;
322 {
323 	u_int	byte_swap_32 (u_int);
324 	u_short	byte_swap_16 (u_short);
325 
326 	struct uscsi_cmd		ucmd;
327 	union scsi_cdb			cdb;
328 	struct scsi_reassign_blk	defect_list;
329 
330 	/*
331 	 * Build and execute the uscsi ioctl
332 	 */
333 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
334 	(void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
335 	(void) memset((char *)&defect_list, 0,
336 		sizeof (struct scsi_reassign_blk));
337 	cdb.scc_cmd = SCMD_REASSIGN_BLOCK;
338 	ucmd.uscsi_cdb = (caddr_t) &cdb;
339 	ucmd.uscsi_cdblen = CDB_GROUP0;
340 	ucmd.uscsi_bufaddr = (caddr_t) &defect_list;
341 	ucmd.uscsi_buflen = sizeof (struct scsi_reassign_blk);
342 	defect_list.length = byte_swap_16 (sizeof (defect_list.defect));
343 	defect_list.defect = byte_swap_32 (bn);
344 	/*
345 	printf ("length - %x %x\n", sizeof (defect_list.defect), defect_list.length);
346 	printf ("defect - %x %x\n", bn, defect_list.defect);
347 	*/
348 	/*
349 	 * Set function flags for driver.
350 	 */
351 	ucmd.uscsi_flags = USCSI_ISOLATE | USCSI_DIAGNOSE | USCSI_SILENT;
352 	ucmd.uscsi_timeout = 30;		/* 30 seconds */
353 
354 	/*
355 	 * Execute the ioctl
356 	 */
357 	if (ioctl(devfd, USCSICMD, &ucmd) == -1)
358 	{
359 		if (errno != ENOTTY)
360 		{
361 			perror ("SCSI hardware re-assign failed");
362 			/*
363 			 * It looks like a failure but by returning success
364 			 * the upper layer will not try to do
365 			 * software remapping.
366 			 */
367 			return (SUCCESS);
368 		}
369 		return (FAILURE);
370 	}
371 	return (SUCCESS);
372 }
373 
374 u_int
375 byte_swap_32 (u_int nav)
376 {
377 	u_int	rc;
378 	rc = ((nav & 0xff000000) >> 24) | ((nav & 0x00ff0000) >> 8) |
379 	     ((nav & 0x0000ff00) << 8)  | ((nav & 0x000000ff) << 24);
380 	return (rc);
381 }
382 
383 u_short
384 byte_swap_16 (u_short niv)
385 {
386 	u_short	rc;
387 	rc = (u_short)((int)(niv & 0xff00) >> 8) | ((niv & 0x00ff) << 8);
388 	return (rc);
389 }
390 
391 int
392 try_hw_remap ()
393 {
394 	struct badsec_lst *blc_p;
395 	int	i;
396 
397 	for (blc_p = gbadsl_chain; blc_p != 0; blc_p = blc_p->bl_nxt)
398 	{
399 
400 		for (i = 0; i < blc_p->bl_cnt; i++)
401 		if (hardware_remap (blc_p->bl_sec[i]) == FAILURE)
402 			return (FAILURE);
403 	}
404 	return (SUCCESS);
405 }
406