1 1.27 mlelstv /* $NetBSD: dkctl.c,v 1.27 2024/09/14 08:30:44 mlelstv Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /* 4 1.1 thorpej * Copyright 2001 Wasabi Systems, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 1.1 thorpej * 9 1.1 thorpej * Redistribution and use in source and binary forms, with or without 10 1.1 thorpej * modification, are permitted provided that the following conditions 11 1.1 thorpej * are met: 12 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 13 1.1 thorpej * notice, this list of conditions and the following disclaimer. 14 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 16 1.1 thorpej * documentation and/or other materials provided with the distribution. 17 1.1 thorpej * 3. All advertising materials mentioning features or use of this software 18 1.1 thorpej * must display the following acknowledgement: 19 1.1 thorpej * This product includes software developed for the NetBSD Project by 20 1.1 thorpej * Wasabi Systems, Inc. 21 1.1 thorpej * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 1.1 thorpej * or promote products derived from this software without specific prior 23 1.1 thorpej * written permission. 24 1.1 thorpej * 25 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 36 1.1 thorpej */ 37 1.1 thorpej 38 1.1 thorpej /* 39 1.1 thorpej * dkctl(8) -- a program to manipulate disks. 40 1.1 thorpej */ 41 1.7 agc #include <sys/cdefs.h> 42 1.7 agc 43 1.7 agc #ifndef lint 44 1.27 mlelstv __RCSID("$NetBSD: dkctl.c,v 1.27 2024/09/14 08:30:44 mlelstv Exp $"); 45 1.7 agc #endif 46 1.7 agc 47 1.1 thorpej #include <sys/param.h> 48 1.1 thorpej #include <sys/ioctl.h> 49 1.24 christos #include <sys/stat.h> 50 1.1 thorpej #include <sys/dkio.h> 51 1.3 darrenr #include <sys/disk.h> 52 1.3 darrenr #include <sys/queue.h> 53 1.1 thorpej #include <err.h> 54 1.1 thorpej #include <errno.h> 55 1.1 thorpej #include <fcntl.h> 56 1.1 thorpej #include <stdio.h> 57 1.1 thorpej #include <stdlib.h> 58 1.22 christos #include <stdbool.h> 59 1.1 thorpej #include <string.h> 60 1.1 thorpej #include <unistd.h> 61 1.1 thorpej #include <util.h> 62 1.1 thorpej 63 1.2 yamt #define YES 1 64 1.2 yamt #define NO 0 65 1.2 yamt 66 1.2 yamt /* I don't think nl_langinfo is suitable in this case */ 67 1.2 yamt #define YES_STR "yes" 68 1.2 yamt #define NO_STR "no" 69 1.2 yamt #define YESNO_ARG YES_STR " | " NO_STR 70 1.2 yamt 71 1.3 darrenr #ifndef PRIdaddr 72 1.3 darrenr #define PRIdaddr PRId64 73 1.3 darrenr #endif 74 1.3 darrenr 75 1.1 thorpej struct command { 76 1.1 thorpej const char *cmd_name; 77 1.1 thorpej const char *arg_names; 78 1.1 thorpej void (*cmd_func)(int, char *[]); 79 1.1 thorpej int open_flags; 80 1.1 thorpej }; 81 1.1 thorpej 82 1.20 joerg static struct command *lookup(const char *); 83 1.20 joerg __dead static void usage(void); 84 1.20 joerg static void run(int, char *[]); 85 1.20 joerg static void showall(void); 86 1.20 joerg 87 1.20 joerg static int fd; /* file descriptor for device */ 88 1.20 joerg static const char *dvname; /* device name */ 89 1.20 joerg static char dvname_store[MAXPATHLEN]; /* for opendisk(3) */ 90 1.20 joerg 91 1.20 joerg static int dkw_sort(const void *, const void *); 92 1.20 joerg static int yesno(const char *); 93 1.20 joerg 94 1.20 joerg static void disk_getcache(int, char *[]); 95 1.20 joerg static void disk_setcache(int, char *[]); 96 1.20 joerg static void disk_synccache(int, char *[]); 97 1.20 joerg static void disk_keeplabel(int, char *[]); 98 1.20 joerg static void disk_badsectors(int, char *[]); 99 1.20 joerg 100 1.20 joerg static void disk_addwedge(int, char *[]); 101 1.20 joerg static void disk_delwedge(int, char *[]); 102 1.20 joerg static void disk_getwedgeinfo(int, char *[]); 103 1.27 mlelstv static void disk_getgeometry(int, char *[]); 104 1.20 joerg static void disk_listwedges(int, char *[]); 105 1.21 mlelstv static void disk_makewedges(int, char *[]); 106 1.20 joerg static void disk_strategy(int, char *[]); 107 1.17 uebayasi 108 1.20 joerg static struct command commands[] = { 109 1.23 wiz { "addwedge", 110 1.23 wiz "name startblk blkcnt ptype", 111 1.23 wiz disk_addwedge, 112 1.2 yamt O_RDWR }, 113 1.2 yamt 114 1.3 darrenr { "badsector", 115 1.3 darrenr "flush | list | retry", 116 1.3 darrenr disk_badsectors, 117 1.3 darrenr O_RDWR }, 118 1.3 darrenr 119 1.9 thorpej { "delwedge", 120 1.9 thorpej "dk", 121 1.9 thorpej disk_delwedge, 122 1.9 thorpej O_RDWR }, 123 1.9 thorpej 124 1.23 wiz { "getcache", 125 1.23 wiz "", 126 1.23 wiz disk_getcache, 127 1.23 wiz O_RDONLY }, 128 1.23 wiz 129 1.9 thorpej { "getwedgeinfo", 130 1.9 thorpej "", 131 1.9 thorpej disk_getwedgeinfo, 132 1.9 thorpej O_RDONLY }, 133 1.9 thorpej 134 1.27 mlelstv { "getgeometry", 135 1.27 mlelstv "", 136 1.27 mlelstv disk_getgeometry, 137 1.27 mlelstv O_RDONLY }, 138 1.27 mlelstv 139 1.23 wiz { "keeplabel", 140 1.23 wiz YESNO_ARG, 141 1.23 wiz disk_keeplabel, 142 1.23 wiz O_RDWR }, 143 1.23 wiz 144 1.9 thorpej { "listwedges", 145 1.9 thorpej "", 146 1.9 thorpej disk_listwedges, 147 1.9 thorpej O_RDONLY }, 148 1.9 thorpej 149 1.21 mlelstv { "makewedges", 150 1.21 mlelstv "", 151 1.21 mlelstv disk_makewedges, 152 1.21 mlelstv O_RDWR }, 153 1.21 mlelstv 154 1.23 wiz { "setcache", 155 1.23 wiz "none | r | w | rw [save]", 156 1.23 wiz disk_setcache, 157 1.23 wiz O_RDWR }, 158 1.23 wiz 159 1.12 yamt { "strategy", 160 1.12 yamt "[name]", 161 1.12 yamt disk_strategy, 162 1.12 yamt O_RDWR }, 163 1.12 yamt 164 1.23 wiz { "synccache", 165 1.23 wiz "[force]", 166 1.23 wiz disk_synccache, 167 1.23 wiz O_RDWR }, 168 1.23 wiz 169 1.1 thorpej { NULL, 170 1.1 thorpej NULL, 171 1.1 thorpej NULL, 172 1.1 thorpej 0 }, 173 1.1 thorpej }; 174 1.1 thorpej 175 1.1 thorpej int 176 1.1 thorpej main(int argc, char *argv[]) 177 1.1 thorpej { 178 1.1 thorpej 179 1.1 thorpej /* Must have at least: device command */ 180 1.17 uebayasi if (argc < 2) 181 1.1 thorpej usage(); 182 1.1 thorpej 183 1.1 thorpej dvname = argv[1]; 184 1.17 uebayasi if (argc == 2) 185 1.17 uebayasi showall(); 186 1.22 christos else 187 1.22 christos run(argc - 2, argv + 2); 188 1.17 uebayasi 189 1.22 christos return EXIT_SUCCESS; 190 1.17 uebayasi } 191 1.1 thorpej 192 1.20 joerg static void 193 1.17 uebayasi run(int argc, char *argv[]) 194 1.17 uebayasi { 195 1.17 uebayasi struct command *command; 196 1.1 thorpej 197 1.22 christos command = lookup(argv[0]); 198 1.1 thorpej 199 1.1 thorpej /* Open the device. */ 200 1.17 uebayasi fd = opendisk(dvname, command->open_flags, dvname_store, 201 1.1 thorpej sizeof(dvname_store), 0); 202 1.1 thorpej if (fd == -1) 203 1.22 christos err(EXIT_FAILURE, "%s", dvname); 204 1.17 uebayasi dvname = dvname_store; 205 1.17 uebayasi 206 1.17 uebayasi (*command->cmd_func)(argc, argv); 207 1.17 uebayasi 208 1.17 uebayasi /* Close the device. */ 209 1.17 uebayasi (void)close(fd); 210 1.17 uebayasi } 211 1.17 uebayasi 212 1.20 joerg static struct command * 213 1.17 uebayasi lookup(const char *name) 214 1.17 uebayasi { 215 1.17 uebayasi int i; 216 1.1 thorpej 217 1.17 uebayasi /* Look up the command. */ 218 1.17 uebayasi for (i = 0; commands[i].cmd_name != NULL; i++) 219 1.17 uebayasi if (strcmp(name, commands[i].cmd_name) == 0) 220 1.17 uebayasi break; 221 1.17 uebayasi if (commands[i].cmd_name == NULL) 222 1.22 christos errx(EXIT_FAILURE, "unknown command: %s", name); 223 1.1 thorpej 224 1.17 uebayasi return &commands[i]; 225 1.1 thorpej } 226 1.1 thorpej 227 1.20 joerg static void 228 1.11 xtraeme usage(void) 229 1.1 thorpej { 230 1.1 thorpej int i; 231 1.1 thorpej 232 1.17 uebayasi fprintf(stderr, 233 1.22 christos "Usage: %s device\n" 234 1.17 uebayasi " %s device command [arg [...]]\n", 235 1.17 uebayasi getprogname(), getprogname()); 236 1.1 thorpej 237 1.1 thorpej fprintf(stderr, " Available commands:\n"); 238 1.1 thorpej for (i = 0; commands[i].cmd_name != NULL; i++) 239 1.1 thorpej fprintf(stderr, "\t%s %s\n", commands[i].cmd_name, 240 1.1 thorpej commands[i].arg_names); 241 1.1 thorpej 242 1.22 christos exit(EXIT_FAILURE); 243 1.1 thorpej } 244 1.1 thorpej 245 1.20 joerg static void 246 1.17 uebayasi showall(void) 247 1.17 uebayasi { 248 1.22 christos static const char *cmds[] = { "strategy", "getcache", "listwedges" }; 249 1.22 christos size_t i; 250 1.22 christos char *args[2]; 251 1.22 christos 252 1.22 christos args[1] = NULL; 253 1.22 christos for (i = 0; i < __arraycount(cmds); i++) { 254 1.22 christos printf("%s:\n", cmds[i]); 255 1.22 christos args[0] = __UNCONST(cmds[i]); 256 1.22 christos run(1, args); 257 1.22 christos putchar('\n'); 258 1.22 christos } 259 1.17 uebayasi } 260 1.17 uebayasi 261 1.20 joerg static void 262 1.12 yamt disk_strategy(int argc, char *argv[]) 263 1.12 yamt { 264 1.12 yamt struct disk_strategy odks; 265 1.12 yamt struct disk_strategy dks; 266 1.12 yamt 267 1.12 yamt memset(&dks, 0, sizeof(dks)); 268 1.12 yamt if (ioctl(fd, DIOCGSTRATEGY, &odks) == -1) { 269 1.12 yamt err(EXIT_FAILURE, "%s: DIOCGSTRATEGY", dvname); 270 1.12 yamt } 271 1.12 yamt 272 1.12 yamt memset(&dks, 0, sizeof(dks)); 273 1.12 yamt switch (argc) { 274 1.22 christos case 1: 275 1.12 yamt /* show the buffer queue strategy used */ 276 1.12 yamt printf("%s: %s\n", dvname, odks.dks_name); 277 1.12 yamt return; 278 1.22 christos case 2: 279 1.12 yamt /* set the buffer queue strategy */ 280 1.22 christos strlcpy(dks.dks_name, argv[1], sizeof(dks.dks_name)); 281 1.12 yamt if (ioctl(fd, DIOCSSTRATEGY, &dks) == -1) { 282 1.12 yamt err(EXIT_FAILURE, "%s: DIOCSSTRATEGY", dvname); 283 1.12 yamt } 284 1.22 christos printf("%s: %s -> %s\n", dvname, odks.dks_name, argv[1]); 285 1.12 yamt break; 286 1.12 yamt default: 287 1.12 yamt usage(); 288 1.12 yamt /* NOTREACHED */ 289 1.12 yamt } 290 1.12 yamt } 291 1.12 yamt 292 1.20 joerg static void 293 1.1 thorpej disk_getcache(int argc, char *argv[]) 294 1.1 thorpej { 295 1.1 thorpej int bits; 296 1.1 thorpej 297 1.1 thorpej if (ioctl(fd, DIOCGCACHE, &bits) == -1) 298 1.22 christos err(EXIT_FAILURE, "%s: getcache", dvname); 299 1.1 thorpej 300 1.1 thorpej if ((bits & (DKCACHE_READ|DKCACHE_WRITE)) == 0) 301 1.1 thorpej printf("%s: No caches enabled\n", dvname); 302 1.1 thorpej else { 303 1.1 thorpej if (bits & DKCACHE_READ) 304 1.1 thorpej printf("%s: read cache enabled\n", dvname); 305 1.1 thorpej if (bits & DKCACHE_WRITE) 306 1.1 thorpej printf("%s: write-back cache enabled\n", dvname); 307 1.1 thorpej } 308 1.1 thorpej 309 1.1 thorpej printf("%s: read cache enable is %schangeable\n", dvname, 310 1.1 thorpej (bits & DKCACHE_RCHANGE) ? "" : "not "); 311 1.1 thorpej printf("%s: write cache enable is %schangeable\n", dvname, 312 1.1 thorpej (bits & DKCACHE_WCHANGE) ? "" : "not "); 313 1.1 thorpej 314 1.1 thorpej printf("%s: cache parameters are %ssavable\n", dvname, 315 1.1 thorpej (bits & DKCACHE_SAVE) ? "" : "not "); 316 1.25 jdolecek 317 1.25 jdolecek #ifdef DKCACHE_FUA 318 1.25 jdolecek printf("%s: cache Force Unit Access (FUA) %ssupported\n", dvname, 319 1.25 jdolecek (bits & DKCACHE_FUA) ? "" : "not "); 320 1.25 jdolecek #endif /* DKCACHE_FUA */ 321 1.25 jdolecek 322 1.25 jdolecek #ifdef DKCACHE_DPO 323 1.25 jdolecek printf("%s: cache Disable Page Out (DPO) %ssupported\n", dvname, 324 1.25 jdolecek (bits & DKCACHE_DPO) ? "" : "not "); 325 1.25 jdolecek #endif /* DKCACHE_DPO */ 326 1.1 thorpej } 327 1.1 thorpej 328 1.20 joerg static void 329 1.1 thorpej disk_setcache(int argc, char *argv[]) 330 1.1 thorpej { 331 1.1 thorpej int bits; 332 1.1 thorpej 333 1.22 christos if (argc > 3 || argc == 1) 334 1.1 thorpej usage(); 335 1.1 thorpej 336 1.22 christos if (strcmp(argv[1], "none") == 0) 337 1.1 thorpej bits = 0; 338 1.22 christos else if (strcmp(argv[1], "r") == 0) 339 1.1 thorpej bits = DKCACHE_READ; 340 1.22 christos else if (strcmp(argv[1], "w") == 0) 341 1.1 thorpej bits = DKCACHE_WRITE; 342 1.22 christos else if (strcmp(argv[1], "rw") == 0) 343 1.1 thorpej bits = DKCACHE_READ|DKCACHE_WRITE; 344 1.1 thorpej else 345 1.1 thorpej usage(); 346 1.1 thorpej 347 1.22 christos if (argc == 3) { 348 1.22 christos if (strcmp(argv[2], "save") == 0) 349 1.1 thorpej bits |= DKCACHE_SAVE; 350 1.1 thorpej else 351 1.1 thorpej usage(); 352 1.1 thorpej } 353 1.1 thorpej 354 1.1 thorpej if (ioctl(fd, DIOCSCACHE, &bits) == -1) 355 1.22 christos err(EXIT_FAILURE, "%s: %s", dvname, argv[0]); 356 1.1 thorpej } 357 1.1 thorpej 358 1.20 joerg static void 359 1.1 thorpej disk_synccache(int argc, char *argv[]) 360 1.1 thorpej { 361 1.1 thorpej int force; 362 1.1 thorpej 363 1.1 thorpej switch (argc) { 364 1.22 christos case 1: 365 1.1 thorpej force = 0; 366 1.1 thorpej break; 367 1.1 thorpej 368 1.22 christos case 2: 369 1.22 christos if (strcmp(argv[1], "force") == 0) 370 1.1 thorpej force = 1; 371 1.1 thorpej else 372 1.1 thorpej usage(); 373 1.1 thorpej break; 374 1.1 thorpej 375 1.1 thorpej default: 376 1.1 thorpej usage(); 377 1.1 thorpej } 378 1.1 thorpej 379 1.1 thorpej if (ioctl(fd, DIOCCACHESYNC, &force) == -1) 380 1.22 christos err(EXIT_FAILURE, "%s: %s", dvname, argv[0]); 381 1.2 yamt } 382 1.2 yamt 383 1.20 joerg static void 384 1.2 yamt disk_keeplabel(int argc, char *argv[]) 385 1.2 yamt { 386 1.2 yamt int keep; 387 1.2 yamt int yn; 388 1.2 yamt 389 1.22 christos if (argc != 2) 390 1.2 yamt usage(); 391 1.2 yamt 392 1.22 christos yn = yesno(argv[1]); 393 1.2 yamt if (yn < 0) 394 1.2 yamt usage(); 395 1.2 yamt 396 1.2 yamt keep = yn == YES; 397 1.2 yamt 398 1.2 yamt if (ioctl(fd, DIOCKLABEL, &keep) == -1) 399 1.22 christos err(EXIT_FAILURE, "%s: %s", dvname, argv[0]); 400 1.3 darrenr } 401 1.3 darrenr 402 1.3 darrenr 403 1.20 joerg static void 404 1.3 darrenr disk_badsectors(int argc, char *argv[]) 405 1.3 darrenr { 406 1.3 darrenr struct disk_badsectors *dbs, *dbs2, buffer[200]; 407 1.3 darrenr SLIST_HEAD(, disk_badsectors) dbstop; 408 1.3 darrenr struct disk_badsecinfo dbsi; 409 1.3 darrenr daddr_t blk, totbad, bad; 410 1.5 dsl u_int32_t count; 411 1.3 darrenr struct stat sb; 412 1.3 darrenr u_char *block; 413 1.6 martin time_t tm; 414 1.3 darrenr 415 1.22 christos if (argc != 2) 416 1.3 darrenr usage(); 417 1.3 darrenr 418 1.22 christos if (strcmp(argv[1], "list") == 0) { 419 1.3 darrenr /* 420 1.3 darrenr * Copy the list of kernel bad sectors out in chunks that fit 421 1.3 darrenr * into buffer[]. Updating dbsi_skip means we don't sit here 422 1.3 darrenr * forever only getting the first chunk that fit in buffer[]. 423 1.3 darrenr */ 424 1.3 darrenr dbsi.dbsi_buffer = (caddr_t)buffer; 425 1.3 darrenr dbsi.dbsi_bufsize = sizeof(buffer); 426 1.3 darrenr dbsi.dbsi_skip = 0; 427 1.3 darrenr dbsi.dbsi_copied = 0; 428 1.3 darrenr dbsi.dbsi_left = 0; 429 1.3 darrenr 430 1.3 darrenr do { 431 1.3 darrenr if (ioctl(fd, DIOCBSLIST, (caddr_t)&dbsi) == -1) 432 1.22 christos err(EXIT_FAILURE, "%s: badsectors list", dvname); 433 1.3 darrenr 434 1.3 darrenr dbs = (struct disk_badsectors *)dbsi.dbsi_buffer; 435 1.3 darrenr for (count = dbsi.dbsi_copied; count > 0; count--) { 436 1.6 martin tm = dbs->dbs_failedat.tv_sec; 437 1.5 dsl printf("%s: blocks %" PRIdaddr " - %" PRIdaddr " failed at %s", 438 1.3 darrenr dvname, dbs->dbs_min, dbs->dbs_max, 439 1.6 martin ctime(&tm)); 440 1.4 darrenr dbs++; 441 1.3 darrenr } 442 1.3 darrenr dbsi.dbsi_skip += dbsi.dbsi_copied; 443 1.3 darrenr } while (dbsi.dbsi_left != 0); 444 1.3 darrenr 445 1.22 christos } else if (strcmp(argv[1], "flush") == 0) { 446 1.3 darrenr if (ioctl(fd, DIOCBSFLUSH) == -1) 447 1.22 christos err(EXIT_FAILURE, "%s: badsectors flush", dvname); 448 1.3 darrenr 449 1.22 christos } else if (strcmp(argv[1], "retry") == 0) { 450 1.3 darrenr /* 451 1.3 darrenr * Enforce use of raw device here because the block device 452 1.3 darrenr * causes access to blocks to be clustered in a larger group, 453 1.3 darrenr * making it impossible to determine which individual sectors 454 1.3 darrenr * are the cause of a problem. 455 1.3 darrenr */ 456 1.3 darrenr if (fstat(fd, &sb) == -1) 457 1.22 christos err(EXIT_FAILURE, "fstat"); 458 1.3 darrenr 459 1.3 darrenr if (!S_ISCHR(sb.st_mode)) { 460 1.3 darrenr fprintf(stderr, "'badsector retry' must be used %s\n", 461 1.3 darrenr "with character device"); 462 1.3 darrenr exit(1); 463 1.3 darrenr } 464 1.3 darrenr 465 1.3 darrenr SLIST_INIT(&dbstop); 466 1.3 darrenr 467 1.3 darrenr /* 468 1.3 darrenr * Build up a copy of the in-kernel list in a number of stages. 469 1.3 darrenr * That the list we build up here is in the reverse order to 470 1.3 darrenr * the kernel's is of no concern. 471 1.3 darrenr */ 472 1.3 darrenr dbsi.dbsi_buffer = (caddr_t)buffer; 473 1.3 darrenr dbsi.dbsi_bufsize = sizeof(buffer); 474 1.3 darrenr dbsi.dbsi_skip = 0; 475 1.3 darrenr dbsi.dbsi_copied = 0; 476 1.3 darrenr dbsi.dbsi_left = 0; 477 1.3 darrenr 478 1.3 darrenr do { 479 1.3 darrenr if (ioctl(fd, DIOCBSLIST, (caddr_t)&dbsi) == -1) 480 1.22 christos err(EXIT_FAILURE, "%s: badsectors list", dvname); 481 1.3 darrenr 482 1.3 darrenr dbs = (struct disk_badsectors *)dbsi.dbsi_buffer; 483 1.3 darrenr for (count = dbsi.dbsi_copied; count > 0; count--) { 484 1.14 dsl dbs2 = malloc(sizeof *dbs2); 485 1.14 dsl if (dbs2 == NULL) 486 1.22 christos err(EXIT_FAILURE, NULL); 487 1.3 darrenr *dbs2 = *dbs; 488 1.3 darrenr SLIST_INSERT_HEAD(&dbstop, dbs2, dbs_next); 489 1.4 darrenr dbs++; 490 1.3 darrenr } 491 1.3 darrenr dbsi.dbsi_skip += dbsi.dbsi_copied; 492 1.3 darrenr } while (dbsi.dbsi_left != 0); 493 1.3 darrenr 494 1.3 darrenr /* 495 1.3 darrenr * Just calculate and print out something that will hopefully 496 1.3 darrenr * provide some useful information about what's going to take 497 1.3 darrenr * place next (if anything.) 498 1.3 darrenr */ 499 1.3 darrenr bad = 0; 500 1.3 darrenr totbad = 0; 501 1.13 rumble if ((block = calloc(1, DEV_BSIZE)) == NULL) 502 1.22 christos err(EXIT_FAILURE, NULL); 503 1.3 darrenr SLIST_FOREACH(dbs, &dbstop, dbs_next) { 504 1.3 darrenr bad++; 505 1.3 darrenr totbad += dbs->dbs_max - dbs->dbs_min + 1; 506 1.3 darrenr } 507 1.3 darrenr 508 1.3 darrenr printf("%s: bad sector clusters %"PRIdaddr 509 1.3 darrenr " total sectors %"PRIdaddr"\n", dvname, bad, totbad); 510 1.3 darrenr 511 1.3 darrenr /* 512 1.3 darrenr * Clear out the kernel's list of bad sectors, ready for us 513 1.3 darrenr * to test all those it thought were bad. 514 1.3 darrenr */ 515 1.3 darrenr if (ioctl(fd, DIOCBSFLUSH) == -1) 516 1.22 christos err(EXIT_FAILURE, "%s: badsectors flush", dvname); 517 1.3 darrenr 518 1.3 darrenr printf("%s: bad sectors flushed\n", dvname); 519 1.3 darrenr 520 1.3 darrenr /* 521 1.3 darrenr * For each entry we obtained from the kernel, retry each 522 1.3 darrenr * individual sector recorded as bad by seeking to it and 523 1.3 darrenr * attempting to read it in. Print out a line item for each 524 1.3 darrenr * bad block we verify. 525 1.3 darrenr * 526 1.3 darrenr * PRIdaddr is used here because the type of dbs_max is daddr_t 527 1.3 darrenr * and that may be either a 32bit or 64bit number(!) 528 1.3 darrenr */ 529 1.3 darrenr SLIST_FOREACH(dbs, &dbstop, dbs_next) { 530 1.3 darrenr printf("%s: Retrying %"PRIdaddr" - %" 531 1.3 darrenr PRIdaddr"\n", dvname, dbs->dbs_min, dbs->dbs_max); 532 1.3 darrenr 533 1.3 darrenr for (blk = dbs->dbs_min; blk <= dbs->dbs_max; blk++) { 534 1.3 darrenr if (lseek(fd, (off_t)blk * DEV_BSIZE, 535 1.3 darrenr SEEK_SET) == -1) { 536 1.5 dsl warn("%s: lseek block %" PRIdaddr "", 537 1.5 dsl dvname, blk); 538 1.3 darrenr continue; 539 1.3 darrenr } 540 1.3 darrenr printf("%s: block %"PRIdaddr" - ", dvname, blk); 541 1.3 darrenr if (read(fd, block, DEV_BSIZE) != DEV_BSIZE) 542 1.3 darrenr printf("failed\n"); 543 1.3 darrenr else 544 1.3 darrenr printf("ok\n"); 545 1.3 darrenr fflush(stdout); 546 1.3 darrenr } 547 1.3 darrenr } 548 1.3 darrenr } 549 1.2 yamt } 550 1.2 yamt 551 1.20 joerg static void 552 1.9 thorpej disk_addwedge(int argc, char *argv[]) 553 1.9 thorpej { 554 1.9 thorpej struct dkwedge_info dkw; 555 1.9 thorpej char *cp; 556 1.9 thorpej daddr_t start; 557 1.9 thorpej uint64_t size; 558 1.9 thorpej 559 1.22 christos if (argc != 5) 560 1.9 thorpej usage(); 561 1.9 thorpej 562 1.19 dholland /* XXX Unicode: dkw_wname is supposed to be utf-8 */ 563 1.22 christos if (strlcpy((char *)dkw.dkw_wname, argv[1], sizeof(dkw.dkw_wname)) >= 564 1.16 christos sizeof(dkw.dkw_wname)) 565 1.22 christos errx(EXIT_FAILURE, "Wedge name too long; max %zd characters", 566 1.9 thorpej sizeof(dkw.dkw_wname) - 1); 567 1.9 thorpej 568 1.22 christos if (strlcpy(dkw.dkw_ptype, argv[4], sizeof(dkw.dkw_ptype)) >= 569 1.15 elad sizeof(dkw.dkw_ptype)) 570 1.22 christos errx(EXIT_FAILURE, "Wedge partition type too long; max %zd characters", 571 1.9 thorpej sizeof(dkw.dkw_ptype) - 1); 572 1.9 thorpej 573 1.9 thorpej errno = 0; 574 1.22 christos start = strtoll(argv[2], &cp, 0); 575 1.9 thorpej if (*cp != '\0') 576 1.22 christos errx(EXIT_FAILURE, "Invalid start block: %s", argv[2]); 577 1.9 thorpej if (errno == ERANGE && (start == LLONG_MAX || 578 1.9 thorpej start == LLONG_MIN)) 579 1.22 christos errx(EXIT_FAILURE, "Start block out of range."); 580 1.9 thorpej if (start < 0) 581 1.22 christos errx(EXIT_FAILURE, "Start block must be >= 0."); 582 1.9 thorpej 583 1.9 thorpej errno = 0; 584 1.22 christos size = strtoull(argv[3], &cp, 0); 585 1.9 thorpej if (*cp != '\0') 586 1.22 christos errx(EXIT_FAILURE, "Invalid block count: %s", argv[3]); 587 1.9 thorpej if (errno == ERANGE && (size == ULLONG_MAX)) 588 1.22 christos errx(EXIT_FAILURE, "Block count out of range."); 589 1.9 thorpej 590 1.9 thorpej dkw.dkw_offset = start; 591 1.9 thorpej dkw.dkw_size = size; 592 1.9 thorpej 593 1.9 thorpej if (ioctl(fd, DIOCAWEDGE, &dkw) == -1) 594 1.22 christos err(EXIT_FAILURE, "%s: %s", dvname, argv[0]); 595 1.18 spz else 596 1.18 spz printf("%s created successfully.\n", dkw.dkw_devname); 597 1.18 spz 598 1.9 thorpej } 599 1.9 thorpej 600 1.20 joerg static void 601 1.9 thorpej disk_delwedge(int argc, char *argv[]) 602 1.9 thorpej { 603 1.9 thorpej struct dkwedge_info dkw; 604 1.9 thorpej 605 1.22 christos if (argc != 2) 606 1.9 thorpej usage(); 607 1.9 thorpej 608 1.22 christos if (strlcpy(dkw.dkw_devname, argv[1], sizeof(dkw.dkw_devname)) >= 609 1.15 elad sizeof(dkw.dkw_devname)) 610 1.22 christos errx(EXIT_FAILURE, "Wedge dk name too long; max %zd characters", 611 1.9 thorpej sizeof(dkw.dkw_devname) - 1); 612 1.9 thorpej 613 1.9 thorpej if (ioctl(fd, DIOCDWEDGE, &dkw) == -1) 614 1.22 christos err(EXIT_FAILURE, "%s: %s", dvname, argv[0]); 615 1.9 thorpej } 616 1.9 thorpej 617 1.20 joerg static void 618 1.9 thorpej disk_getwedgeinfo(int argc, char *argv[]) 619 1.9 thorpej { 620 1.9 thorpej struct dkwedge_info dkw; 621 1.9 thorpej 622 1.22 christos if (argc != 1) 623 1.9 thorpej usage(); 624 1.9 thorpej 625 1.9 thorpej if (ioctl(fd, DIOCGWEDGEINFO, &dkw) == -1) 626 1.22 christos err(EXIT_FAILURE, "%s: getwedgeinfo", dvname); 627 1.9 thorpej 628 1.9 thorpej printf("%s at %s: %s\n", dkw.dkw_devname, dkw.dkw_parent, 629 1.9 thorpej dkw.dkw_wname); /* XXX Unicode */ 630 1.10 martin printf("%s: %"PRIu64" blocks at %"PRId64", type: %s\n", 631 1.9 thorpej dkw.dkw_devname, dkw.dkw_size, dkw.dkw_offset, dkw.dkw_ptype); 632 1.9 thorpej } 633 1.9 thorpej 634 1.20 joerg static void 635 1.27 mlelstv disk_getgeometry(int argc, char *argv[]) 636 1.27 mlelstv { 637 1.27 mlelstv off_t bytes; 638 1.27 mlelstv u_int secsize; 639 1.27 mlelstv 640 1.27 mlelstv if (argc != 1) 641 1.27 mlelstv usage(); 642 1.27 mlelstv 643 1.27 mlelstv if (ioctl(fd, DIOCGMEDIASIZE, &bytes) == -1) 644 1.27 mlelstv err(EXIT_FAILURE, "%s: getmediasize", dvname); 645 1.27 mlelstv 646 1.27 mlelstv secsize = DEV_BSIZE; 647 1.27 mlelstv if (ioctl(fd, DIOCGSECTORSIZE, &secsize) == -1) 648 1.27 mlelstv warn("%s: getsectorsize", dvname); 649 1.27 mlelstv 650 1.27 mlelstv printf("%s: %"PRIu64" bytes in %"PRIu64" blocks of %u bytes\n", 651 1.27 mlelstv dvname, bytes, bytes/secsize, secsize); 652 1.27 mlelstv } 653 1.27 mlelstv 654 1.27 mlelstv static void 655 1.9 thorpej disk_listwedges(int argc, char *argv[]) 656 1.9 thorpej { 657 1.9 thorpej struct dkwedge_info *dkw; 658 1.9 thorpej struct dkwedge_list dkwl; 659 1.9 thorpej size_t bufsize; 660 1.9 thorpej u_int i; 661 1.22 christos int c; 662 1.22 christos bool error, quiet; 663 1.22 christos 664 1.22 christos optreset = 1; 665 1.22 christos optind = 1; 666 1.22 christos quiet = error = false; 667 1.22 christos while ((c = getopt(argc, argv, "qe")) != -1) 668 1.22 christos switch (c) { 669 1.22 christos case 'e': 670 1.22 christos error = true; 671 1.22 christos break; 672 1.22 christos case 'q': 673 1.22 christos quiet = true; 674 1.22 christos break; 675 1.22 christos default: 676 1.22 christos usage(); 677 1.22 christos } 678 1.22 christos 679 1.22 christos argc -= optind; 680 1.22 christos argv += optind; 681 1.9 thorpej 682 1.9 thorpej if (argc != 0) 683 1.9 thorpej usage(); 684 1.9 thorpej 685 1.9 thorpej dkw = NULL; 686 1.9 thorpej dkwl.dkwl_buf = dkw; 687 1.9 thorpej dkwl.dkwl_bufsize = 0; 688 1.9 thorpej 689 1.9 thorpej for (;;) { 690 1.9 thorpej if (ioctl(fd, DIOCLWEDGES, &dkwl) == -1) 691 1.22 christos err(EXIT_FAILURE, "%s: listwedges", dvname); 692 1.9 thorpej if (dkwl.dkwl_nwedges == dkwl.dkwl_ncopied) 693 1.9 thorpej break; 694 1.9 thorpej bufsize = dkwl.dkwl_nwedges * sizeof(*dkw); 695 1.9 thorpej if (dkwl.dkwl_bufsize < bufsize) { 696 1.9 thorpej dkw = realloc(dkwl.dkwl_buf, bufsize); 697 1.9 thorpej if (dkw == NULL) 698 1.22 christos errx(EXIT_FAILURE, "%s: listwedges: unable to " 699 1.9 thorpej "allocate wedge info buffer", dvname); 700 1.9 thorpej dkwl.dkwl_buf = dkw; 701 1.9 thorpej dkwl.dkwl_bufsize = bufsize; 702 1.9 thorpej } 703 1.9 thorpej } 704 1.9 thorpej 705 1.9 thorpej if (dkwl.dkwl_nwedges == 0) { 706 1.22 christos if (!quiet) 707 1.22 christos printf("%s: no wedges configured\n", dvname); 708 1.22 christos if (error) 709 1.22 christos exit(EXIT_FAILURE); 710 1.9 thorpej return; 711 1.9 thorpej } 712 1.9 thorpej 713 1.26 kre if (quiet) 714 1.26 kre return; 715 1.26 kre 716 1.17 uebayasi qsort(dkw, dkwl.dkwl_nwedges, sizeof(*dkw), dkw_sort); 717 1.17 uebayasi 718 1.9 thorpej printf("%s: %u wedge%s:\n", dvname, dkwl.dkwl_nwedges, 719 1.9 thorpej dkwl.dkwl_nwedges == 1 ? "" : "s"); 720 1.9 thorpej for (i = 0; i < dkwl.dkwl_nwedges; i++) { 721 1.10 martin printf("%s: %s, %"PRIu64" blocks at %"PRId64", type: %s\n", 722 1.9 thorpej dkw[i].dkw_devname, 723 1.9 thorpej dkw[i].dkw_wname, /* XXX Unicode */ 724 1.9 thorpej dkw[i].dkw_size, dkw[i].dkw_offset, dkw[i].dkw_ptype); 725 1.9 thorpej } 726 1.9 thorpej } 727 1.9 thorpej 728 1.21 mlelstv static void 729 1.21 mlelstv disk_makewedges(int argc, char *argv[]) 730 1.21 mlelstv { 731 1.21 mlelstv int bits; 732 1.21 mlelstv 733 1.22 christos if (argc != 1) 734 1.21 mlelstv usage(); 735 1.21 mlelstv 736 1.21 mlelstv if (ioctl(fd, DIOCMWEDGES, &bits) == -1) 737 1.22 christos err(EXIT_FAILURE, "%s: %s", dvname, argv[0]); 738 1.21 mlelstv else 739 1.21 mlelstv printf("successfully scanned %s.\n", dvname); 740 1.21 mlelstv } 741 1.21 mlelstv 742 1.20 joerg static int 743 1.17 uebayasi dkw_sort(const void *a, const void *b) 744 1.17 uebayasi { 745 1.17 uebayasi const struct dkwedge_info *dkwa = a, *dkwb = b; 746 1.17 uebayasi const daddr_t oa = dkwa->dkw_offset, ob = dkwb->dkw_offset; 747 1.17 uebayasi 748 1.17 uebayasi return (oa < ob) ? -1 : (oa > ob) ? 1 : 0; 749 1.17 uebayasi } 750 1.17 uebayasi 751 1.2 yamt /* 752 1.2 yamt * return YES, NO or -1. 753 1.2 yamt */ 754 1.20 joerg static int 755 1.2 yamt yesno(const char *p) 756 1.2 yamt { 757 1.2 yamt 758 1.2 yamt if (!strcmp(p, YES_STR)) 759 1.2 yamt return YES; 760 1.2 yamt if (!strcmp(p, NO_STR)) 761 1.2 yamt return NO; 762 1.2 yamt return -1; 763 1.1 thorpej } 764