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