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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
28 /* All Rights Reserved */
31 * Copyrighted as an unpublished work.
32 * (c) Copyright INTERACTIVE Systems Corporation 1986, 1988, 1990
33 * All rights reserved.
39 #include <sys/types.h>
40 #include <sys/param.h>
42 #include <sys/mkdev.h>
50 #include <sys/scsi/generic/commands.h>
51 #include <sys/scsi/impl/commands.h>
52 #include <sys/scsi/impl/uscsi.h>
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 */
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);
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
);
78 main(int argc
, char *argv
[])
83 static char options
[] = "Ipa:f:";
89 struct extpartition
*part
= NULL
;
97 FILE *badsecfd
= NULL
;
100 while ((c
= getopt(argc
, argv
, options
)) != EOF
) {
110 for (; *nxtarg
!= '\0'; )
111 add_gbad(strtol(nxtarg
, &nxtarg
, 0));
114 if ((badsecfd
= fopen(optarg
, "r")) == NULL
) {
115 (void) fprintf(stderr
,
116 "%s: unable to open %s file\n",
127 /* get the last argument -- device stanza */
128 if (argc
!= optind
+1) {
129 (void) fprintf(stderr
, "Missing disk device name\n");
133 devname
= argv
[optind
];
135 if (stat(devname
, &statbuf
)) {
136 (void) fprintf(stderr
, "%s: invalid device %s, stat failed\n",
141 if ((statbuf
.st_mode
& S_IFMT
) != S_IFCHR
) {
142 (void) fprintf(stderr
, "%s: device %s is not character"
143 " special\n", progname
, devname
);
147 minor_val
= minor(statbuf
.st_rdev
);
149 * NEED A DEFINE FOR THE PHYSICAL BIT (0x10)
151 if ((minor_val
& 0x10) == 0) {
152 (void) fprintf(stderr
, "%s: device %s is not a physical"
153 " slice\n", progname
, devname
);
157 if ((minor_val
% V_NUMPAR
) != 0) {
158 (void) fprintf(stderr
, "%s: device %s is not a slice 0"
159 " device\n", progname
, devname
);
163 if ((devfd
= open(devname
, O_RDWR
)) == -1) {
164 (void) fprintf(stderr
, "%s: open of %s failed\n",
169 if ((ioctl(devfd
, DKIOCGGEOM
, &dkg
)) == -1) {
170 (void) fprintf(stderr
, "%s: unable to get disk geometry.\n",
176 if (ioctl(devfd
, DKIOCGEXTVTOC
, &vtoc
) == -1) {
177 (void) fprintf(stderr
, "%s: could not get VTOC.\n", progname
);
182 if ((vtoc
.v_sanity
!= VTOC_SANE
) || (vtoc
.v_version
!= V_VERSION
)) {
183 (void) fprintf(stderr
, "%s: invalid VTOC found.\n", progname
);
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
]);
203 * If init_flag is set, run to completion.
205 if (gbadsl_chain_cnt
== 0 && init_flag
== 0)
207 * No defects and not initializing
211 if (gbadsl_chain_cnt
!= 0)
213 if (try_hw_remap() == SUCCESS
)
219 for (i
= 0; i
< V_NUMPAR
&& alts_slice
== -1; i
++)
221 if (vtoc
.v_part
[i
].p_tag
== V_ALTSCTR
)
224 part
= &vtoc
.v_part
[i
];
227 if (alts_slice
== -1)
229 (void) fprintf(stderr
, "%s: No alternates slice.\n", progname
);
233 (void) sprintf(numbuf
, "%d", alts_slice
);
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
);
248 (void) print_altsec(part
);
251 (void) updatebadsec(part
, init_flag
);
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");
262 (void) fclose(badsecfd
);
263 (void) close(alts_fd
);
270 * Give a (not so) concise message on how to use this program.
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");
288 * read in the additional growing bad sectors
291 rd_gbad(FILE *badsecfd
)
296 status
= fscanf(badsecfd
, "%d", &badsec_entry
);
297 while (status
!= EOF
) {
298 add_gbad(badsec_entry
);
299 status
= fscanf(badsecfd
, "%d", &badsec_entry
);
304 add_gbad(int badsec_entry
)
306 struct badsec_lst
*blc_p
;
309 blc_p
= (struct badsec_lst
*)malloc(BADSLSZ
);
311 (void) fprintf(stderr
, "Unable to allocate memory"
312 " for additional bad sectors\n");
315 gbadsl_chain
= blc_p
;
319 for (blc_p
= gbadsl_chain
; blc_p
->bl_nxt
; )
320 blc_p
= blc_p
->bl_nxt
;
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");
329 blc_p
= blc_p
->bl_nxt
;
333 blc_p
->bl_sec
[blc_p
->bl_cnt
++] = badsec_entry
;
338 * Map a block using hardware (SCSI) techniques.
345 uint_t
byte_swap_32(uint_t
);
346 ushort_t
byte_swap_16(ushort_t
);
348 struct uscsi_cmd ucmd
;
350 struct scsi_reassign_blk defect_list
;
353 * Build and execute the uscsi ioctl
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
);
367 * Set function flags for driver.
369 ucmd
.uscsi_flags
= USCSI_ISOLATE
| USCSI_DIAGNOSE
| USCSI_SILENT
;
370 ucmd
.uscsi_timeout
= 30; /* 30 seconds */
375 if (ioctl(devfd
, USCSICMD
, &ucmd
) == -1)
379 perror("SCSI hardware re-assign failed");
381 * It looks like a failure but by returning success
382 * the upper layer will not try to do
383 * software remapping.
393 byte_swap_32(uint_t nav
)
396 rc
= ((nav
& 0xff000000) >> 24) | ((nav
& 0x00ff0000) >> 8) |
397 ((nav
& 0x0000ff00) << 8) | ((nav
& 0x000000ff) << 24);
402 byte_swap_16(ushort_t niv
)
405 rc
= (ushort_t
)((int)(niv
& 0xff00) >> 8) | ((niv
& 0x00ff) << 8);
412 struct badsec_lst
*blc_p
;
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
)