xref: /titanic_52/usr/src/cmd/addbadsec/addbadsec.c (revision 1a7c1b724419d3cb5fa6eea75123c6b2060ba31b)
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 2003 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 void
68 main(argc, argv)
69 int	argc;
70 char	*argv[];
71 {
72 	extern int	optind;
73 	extern char	*optarg;
74 
75 	static char     options[] = "Ipa:f:";
76 	char		numbuf[100];
77 	char		*nxtarg;
78 	char		*alts_name;
79 	minor_t 	minor_val;
80 	struct stat 	statbuf;
81 	struct partition	*part = NULL;
82 	int		alts_slice = -1;
83 	int		l;
84 	int		p;
85 	int		init_flag = 0;
86 	int		print_flag = 0;
87 	int 		c;
88 	int 		i;
89 	FILE		*badsecfd = NULL;
90 	struct badsec_lst *blc_p;
91 
92 	progname = argv[0];
93 	while ( (c=getopt(argc, argv, options)) != EOF ) {
94 		switch (c) {
95 		case 'I':
96 			init_flag = 1;
97 			break;
98 		case 'p':
99 			print_flag = 1;
100 			break;
101 		case 'a':
102 			nxtarg = optarg;
103 			for (;*nxtarg != '\0';)
104 				add_gbad(strtol(nxtarg, &nxtarg, 0));
105 			break;
106 		case 'f':
107 			if ((badsecfd = fopen(optarg, "r")) == NULL) {
108 				fprintf(stderr, "%s: unable to open %s file\n", progname, optarg);
109 				exit(1);
110 			}
111 			break;
112 		default:
113 			giveusage();
114 			exit(2);
115 		}
116 	}
117 
118 		/* get the last argument -- device stanza */
119 	if (argc != optind+1) {
120 		fprintf(stderr, "Missing disk device name\n");
121 		giveusage();
122 		exit(3);
123 	}
124 	devname = argv[optind];
125 
126 	if (stat(devname, &statbuf)) {
127 		fprintf(stderr, "%s: invalid device %s, stat failed\n", progname, devname);
128 		giveusage();
129 		exit(4);
130 	}
131 	if ((statbuf.st_mode & S_IFMT) != S_IFCHR) {
132 		fprintf(stderr, "%s: device %s is not character special\n", progname, devname);
133 		giveusage();
134 		exit(5);
135 	}
136 	minor_val = minor(statbuf.st_rdev);
137 	/*
138 	 * NEED A DEFINE FOR THE PHYSICAL BIT (0x10)
139 	 */
140 	if ((minor_val & 0x10) == 0) {
141 		fprintf(stderr, "%s: device %s is not a physical slice\n", progname, devname);
142 		giveusage();
143 		exit(6);
144 	}
145 	if ((minor_val % V_NUMPAR) != 0) {
146 		fprintf(stderr, "%s: device %s is not a slice 0 device\n", progname, devname);
147 		giveusage();
148 		exit(7);
149 	}
150 	if ((devfd=open(devname, O_RDWR)) == -1) {
151 		fprintf(stderr, "%s: open of %s failed\n", progname ,devname);
152 		perror("");
153 		exit(8);
154 	}
155 	if ((ioctl (devfd, DKIOCGGEOM, &dkg)) == -1) {
156 		fprintf(stderr, "%s: unable to get disk geometry.\n", progname);
157 		perror("");
158 		exit(9);
159 	}
160 
161 	if (ioctl(devfd, DKIOCGVTOC, &vtoc) == -1)
162 	{
163 		fprintf(stderr, "%s: could not get VTOC.\n", progname);
164 		giveusage();
165 		exit(14);
166 	}
167 
168 	if ((vtoc.v_sanity != VTOC_SANE) || (vtoc.v_version != V_VERSION)) {
169 		fprintf(stderr, "%s: invalid VTOC found.\n", progname);
170 		giveusage();
171 		exit(15);
172 	}
173 	if (badsecfd)
174 		rd_gbad(badsecfd);
175 
176 #ifdef ADDBAD_DEBUG
177 	printf("\n main: Total bad sectors found= %d\n", gbadsl_chain_cnt);
178 	for (blc_p=gbadsl_chain; blc_p; blc_p=blc_p->bl_nxt) {
179 		for (i=0; i<blc_p->bl_cnt; i++)
180 			printf(" badsec=%d ", blc_p->bl_sec[i]);
181 	}
182 	printf("\n");
183 #endif
184 #ifdef PPP
185 	/*
186 	 * If init_flag is set, run to completion.
187 	 */
188 	if (gbadsl_chain_cnt == 0 && init_flag == 0)
189 		/*
190 		 * No defects and not initializing
191 		 */
192 		exit (0);
193 #endif
194 	if (gbadsl_chain_cnt != 0)
195 	{
196 		if (try_hw_remap () == SUCCESS)
197 			exit (0);
198 	}
199 	/*
200 	 * get ALTS slice
201 	 */
202 	for (i = 0; i < V_NUMPAR && alts_slice == -1; i++)
203 	{
204 		if (vtoc.v_part[i].p_tag == V_ALTSCTR)
205 		{
206 			alts_slice = i;
207 			part = &vtoc.v_part[i];
208 		}
209 	}
210 	if (alts_slice == -1)
211 	{
212 		fprintf(stderr, "%s: No alternates slice.\n", progname);
213 		exit(16);
214 	}
215 	l = strlen (devname);
216 	sprintf (numbuf, "%d", alts_slice);
217 	p = strlen (numbuf);
218 	alts_name = (char *)malloc (l + p);
219 	strcpy (alts_name, devname);
220 	alts_name[l - 2] = 's';
221 	strcpy (&alts_name[l - 1], numbuf);
222 	alts_name[l + p - 1] = '\0';
223 	if ((alts_fd=open(alts_name, O_RDWR)) == -1) {
224 		fprintf(stderr, "%s: open of %s failed\n", progname ,alts_name);
225 		perror("");
226 		exit(9);
227 	}
228 	if (print_flag)
229 	{
230 		print_altsec (part);
231 		exit (0);
232 	}
233 	updatebadsec(part, init_flag);
234 	wr_altsctr();
235 
236 	if (ioctl(devfd, DKIOCADDBAD, NULL) == -1) {
237 		fprintf(stderr,  "Warning: DKIOCADDBAD io control failed. System must be re-booted\n");
238 		fprintf(stderr, "for alternate sectors to be usable.\n");
239 		exit(17);
240 	}
241 	sync();
242 
243 	fclose(badsecfd);
244 	close (alts_fd);
245 	close (devfd);
246 	exit(0);
247 }
248 
249 /*
250  * Giveusage ()
251  * Give a (not so) concise message on how to use this program.
252  */
253 giveusage()
254 {
255 	fprintf(stderr, "%s [-p] [-a sector] [-f filename] raw-device\n", progname);
256 	fprintf(stderr, "	p - Print existing bad block map\n");
257 	fprintf(stderr, "	a - Add the given sectors to the bad block list\n");
258 	fprintf(stderr, "	f - Add the sectors from <filename> to the bad block list\n");
259 	if (devfd)
260 		close(devfd);
261 }
262 
263 
264 /*
265  *	read in the additional growing bad sectors
266  */
267 rd_gbad(badsecfd)
268 FILE	*badsecfd;
269 {
270 	int	badsec_entry;
271 	int	status;
272 
273 	status = fscanf(badsecfd, "%d", &badsec_entry);
274 	while (status!=EOF) {
275 		add_gbad(badsec_entry);
276 		status = fscanf(badsecfd, "%d", &badsec_entry);
277 	}
278 }
279 
280 add_gbad(badsec_entry)
281 int	badsec_entry;
282 {
283 	struct badsec_lst *blc_p;
284 
285 	if (!gbadsl_chain) {
286 		blc_p = (struct badsec_lst *)malloc(BADSLSZ);
287 		if (!blc_p) {
288 			fprintf(stderr, "Unable to allocate memory for additional bad sectors\n");
289 			exit(18);
290 		}
291 		gbadsl_chain = blc_p;
292 		blc_p->bl_cnt = 0;
293 		blc_p->bl_nxt = 0;
294 	}
295 	for (blc_p = gbadsl_chain; blc_p->bl_nxt; )
296 		blc_p = blc_p->bl_nxt;
297 
298 	if (blc_p->bl_cnt == MAXBLENT) {
299 		blc_p->bl_nxt = (struct badsec_lst *)malloc(BADSLSZ);
300 		if (!blc_p->bl_nxt) {
301 			fprintf(stderr, "Unable to allocate memory for additional bad sectors\n");
302 			exit(19);
303 		}
304 		blc_p = blc_p->bl_nxt;
305 		blc_p->bl_cnt = 0;
306 		blc_p->bl_nxt = 0;
307 	}
308 	blc_p->bl_sec[blc_p->bl_cnt++] = badsec_entry;
309 	gbadsl_chain_cnt++;
310 }
311 
312 /*
313  * Map a block using hardware (SCSI) techniques.
314  */
315 /*ARGSUSED*/
316 int
317 hardware_remap (bn)
318 int	bn;
319 {
320 	u_int	byte_swap_32 (u_int);
321 	u_short	byte_swap_16 (u_short);
322 
323 	struct uscsi_cmd		ucmd;
324 	union scsi_cdb			cdb;
325 	struct scsi_reassign_blk	defect_list;
326 
327 	/*
328 	 * Build and execute the uscsi ioctl
329 	 */
330 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
331 	(void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
332 	(void) memset((char *)&defect_list, 0,
333 		sizeof (struct scsi_reassign_blk));
334 	cdb.scc_cmd = SCMD_REASSIGN_BLOCK;
335 	ucmd.uscsi_cdb = (caddr_t) &cdb;
336 	ucmd.uscsi_cdblen = CDB_GROUP0;
337 	ucmd.uscsi_bufaddr = (caddr_t) &defect_list;
338 	ucmd.uscsi_buflen = sizeof (struct scsi_reassign_blk);
339 	defect_list.length = byte_swap_16 (sizeof (defect_list.defect));
340 	defect_list.defect = byte_swap_32 (bn);
341 	/*
342 	printf ("length - %x %x\n", sizeof (defect_list.defect), defect_list.length);
343 	printf ("defect - %x %x\n", bn, defect_list.defect);
344 	*/
345 	/*
346 	 * Set function flags for driver.
347 	 */
348 	ucmd.uscsi_flags = USCSI_ISOLATE | USCSI_DIAGNOSE | USCSI_SILENT;
349 	ucmd.uscsi_timeout = 30;		/* 30 seconds */
350 
351 	/*
352 	 * Execute the ioctl
353 	 */
354 	if (ioctl(devfd, USCSICMD, &ucmd) == -1)
355 	{
356 		if (errno != ENOTTY)
357 		{
358 			perror ("SCSI hardware re-assign failed");
359 			/*
360 			 * It looks like a failure but by returning success
361 			 * the upper layer will not try to do
362 			 * software remapping.
363 			 */
364 			return (SUCCESS);
365 		}
366 		return (FAILURE);
367 	}
368 	return (SUCCESS);
369 }
370 
371 u_int
372 byte_swap_32 (u_int nav)
373 {
374 	u_int	rc;
375 	rc = ((nav & 0xff000000) >> 24) | ((nav & 0x00ff0000) >> 8) |
376 	     ((nav & 0x0000ff00) << 8)  | ((nav & 0x000000ff) << 24);
377 	return (rc);
378 }
379 
380 u_short
381 byte_swap_16 (u_short niv)
382 {
383 	u_short	rc;
384 	rc = (u_short)((int)(niv & 0xff00) >> 8) | ((niv & 0x00ff) << 8);
385 	return (rc);
386 }
387 
388 try_hw_remap ()
389 {
390 	struct badsec_lst *blc_p;
391 	int	i;
392 
393 	for (blc_p = gbadsl_chain; blc_p != 0; blc_p = blc_p->bl_nxt)
394 	{
395 
396 		for (i = 0; i < blc_p->bl_cnt; i++)
397 		if (hardware_remap (blc_p->bl_sec[i]) == FAILURE)
398 			return (FAILURE);
399 	}
400 	return (SUCCESS);
401 }
402