0
|
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 "@(#)addbadsec.c 1.13 05/08/01 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 }
|