1 1.42 riastrad /* $NetBSD: scsictl.c,v 1.42 2024/11/10 01:55:06 riastradh Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /*- 4 1.18 thorpej * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * This code is derived from software contributed to The NetBSD Foundation 8 1.1 thorpej * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 1.1 thorpej * NASA Ames Research Center. 10 1.1 thorpej * 11 1.1 thorpej * Redistribution and use in source and binary forms, with or without 12 1.1 thorpej * modification, are permitted provided that the following conditions 13 1.1 thorpej * are met: 14 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 15 1.1 thorpej * notice, this list of conditions and the following disclaimer. 16 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 18 1.1 thorpej * documentation and/or other materials provided with the distribution. 19 1.1 thorpej * 20 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.1 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 31 1.1 thorpej */ 32 1.1 thorpej 33 1.1 thorpej /* 34 1.1 thorpej * scsictl(8) - a program to manipulate SCSI devices and busses. 35 1.1 thorpej */ 36 1.20 agc #include <sys/cdefs.h> 37 1.20 agc 38 1.20 agc #ifndef lint 39 1.42 riastrad __RCSID("$NetBSD: scsictl.c,v 1.42 2024/11/10 01:55:06 riastradh Exp $"); 40 1.20 agc #endif 41 1.20 agc 42 1.1 thorpej #include <sys/param.h> 43 1.1 thorpej #include <sys/ioctl.h> 44 1.1 thorpej #include <sys/scsiio.h> 45 1.1 thorpej #include <err.h> 46 1.1 thorpej #include <errno.h> 47 1.1 thorpej #include <fcntl.h> 48 1.25 ginsbach #include <limits.h> 49 1.1 thorpej #include <stdio.h> 50 1.1 thorpej #include <stdlib.h> 51 1.41 mlelstv #include <stdbool.h> 52 1.1 thorpej #include <string.h> 53 1.1 thorpej #include <unistd.h> 54 1.1 thorpej #include <util.h> 55 1.1 thorpej 56 1.27 thorpej #include <dev/scsipi/scsi_spc.h> 57 1.1 thorpej #include <dev/scsipi/scsipi_all.h> 58 1.1 thorpej #include <dev/scsipi/scsi_disk.h> 59 1.1 thorpej #include <dev/scsipi/scsipiconf.h> 60 1.1 thorpej 61 1.1 thorpej #include "extern.h" 62 1.1 thorpej 63 1.1 thorpej struct command { 64 1.1 thorpej const char *cmd_name; 65 1.6 hubertf const char *arg_names; 66 1.26 xtraeme void (*cmd_func)(int, char *[]); 67 1.1 thorpej }; 68 1.1 thorpej 69 1.33 joerg __dead static void usage(void); 70 1.1 thorpej 71 1.35 jakllsch static int fd; /* file descriptor for device */ 72 1.35 jakllsch const char *dvname; /* device name */ 73 1.35 jakllsch static char dvname_store[MAXPATHLEN]; /* for opendisk(3) */ 74 1.35 jakllsch static const char *cmdname; /* command user issued */ 75 1.35 jakllsch static struct scsi_addr dvaddr; /* SCSI device's address */ 76 1.35 jakllsch 77 1.35 jakllsch static void device_defects(int, char *[]); 78 1.35 jakllsch static void device_format(int, char *[]); 79 1.35 jakllsch static void device_identify(int, char *[]); 80 1.35 jakllsch static void device_reassign(int, char *[]); 81 1.35 jakllsch static void device_release(int, char *[]); 82 1.35 jakllsch static void device_reserve(int, char *[]); 83 1.35 jakllsch static void device_reset(int, char *[]); 84 1.35 jakllsch static void device_debug(int, char *[]); 85 1.35 jakllsch static void device_prevent(int, char *[]); 86 1.35 jakllsch static void device_allow(int, char *[]); 87 1.35 jakllsch static void device_start(int, char *[]); 88 1.35 jakllsch static void device_stop(int, char *[]); 89 1.35 jakllsch static void device_tur(int, char *[]); 90 1.35 jakllsch static void device_getcache(int, char *[]); 91 1.35 jakllsch static void device_setcache(int, char *[]); 92 1.35 jakllsch static void device_flushcache(int, char *[]); 93 1.35 jakllsch static void device_setspeed(int, char *[]); 94 1.39 flxd static void device_getrealloc(int, char *[]); 95 1.39 flxd static void device_setrealloc(int, char *[]); 96 1.40 mlelstv static void device_reportluns(int, char *[]); 97 1.1 thorpej 98 1.35 jakllsch static struct command device_commands[] = { 99 1.25 ginsbach { "defects", "[primary] [grown] [block|byte|physical]", 100 1.25 ginsbach device_defects }, 101 1.16 mjacob { "format", "[blocksize [immediate]]", device_format }, 102 1.41 mlelstv { "identify", "[vpd]", device_identify }, 103 1.7 mjl { "reassign", "blkno [blkno [...]]", device_reassign }, 104 1.16 mjacob { "release", "", device_release }, 105 1.16 mjacob { "reserve", "", device_reserve }, 106 1.7 mjl { "reset", "", device_reset }, 107 1.19 petrov { "debug", "level", device_debug }, 108 1.22 mycroft { "prevent", "", device_prevent }, 109 1.22 mycroft { "allow", "", device_allow }, 110 1.16 mjacob { "start", "", device_start }, 111 1.16 mjacob { "stop", "", device_stop }, 112 1.16 mjacob { "tur", "", device_tur }, 113 1.18 thorpej { "getcache", "", device_getcache }, 114 1.18 thorpej { "setcache", "none|r|w|rw [save]", device_setcache }, 115 1.21 mycroft { "flushcache", "", device_flushcache }, 116 1.29 bouyer { "setspeed", "[speed]", device_setspeed }, 117 1.39 flxd { "getrealloc", "", device_getrealloc }, 118 1.39 flxd { "setrealloc", "none|r|w|rw [save]", device_setrealloc }, 119 1.40 mlelstv { "reportluns", "normal|wellknown|all|#", device_reportluns }, 120 1.7 mjl { NULL, NULL, NULL }, 121 1.1 thorpej }; 122 1.1 thorpej 123 1.35 jakllsch static void bus_reset(int, char *[]); 124 1.35 jakllsch static void bus_scan(int, char *[]); 125 1.35 jakllsch static void bus_detach(int, char *[]); 126 1.1 thorpej 127 1.35 jakllsch static struct command bus_commands[] = { 128 1.7 mjl { "reset", "", bus_reset }, 129 1.7 mjl { "scan", "target lun", bus_scan }, 130 1.14 bouyer { "detach", "target lun", bus_detach }, 131 1.6 hubertf { NULL, NULL, NULL }, 132 1.1 thorpej }; 133 1.1 thorpej 134 1.1 thorpej int 135 1.26 xtraeme main(int argc, char *argv[]) 136 1.1 thorpej { 137 1.1 thorpej struct command *commands; 138 1.1 thorpej int i; 139 1.1 thorpej 140 1.1 thorpej /* Must have at least: device command */ 141 1.1 thorpej if (argc < 3) 142 1.1 thorpej usage(); 143 1.1 thorpej 144 1.1 thorpej /* Skip program name, get and skip device name and command. */ 145 1.1 thorpej dvname = argv[1]; 146 1.1 thorpej cmdname = argv[2]; 147 1.1 thorpej argv += 3; 148 1.1 thorpej argc -= 3; 149 1.1 thorpej 150 1.1 thorpej /* 151 1.1 thorpej * Open the device and determine if it's a scsibus or an actual 152 1.1 thorpej * device. Devices respond to the SCIOCIDENTIFY ioctl. 153 1.1 thorpej */ 154 1.1 thorpej fd = opendisk(dvname, O_RDWR, dvname_store, sizeof(dvname_store), 0); 155 1.1 thorpej if (fd == -1) { 156 1.1 thorpej if (errno == ENOENT) { 157 1.1 thorpej /* 158 1.1 thorpej * Device doesn't exist. Probably trying to open 159 1.1 thorpej * a device which doesn't use disk semantics for 160 1.3 thorpej * device name. Try again, specifying "cooked", 161 1.3 thorpej * which leaves off the "r" in front of the device's 162 1.3 thorpej * name. 163 1.1 thorpej */ 164 1.3 thorpej fd = opendisk(dvname, O_RDWR, dvname_store, 165 1.3 thorpej sizeof(dvname_store), 1); 166 1.1 thorpej if (fd == -1) 167 1.1 thorpej err(1, "%s", dvname); 168 1.5 jwise } else 169 1.5 jwise err(1, "%s", dvname); 170 1.1 thorpej } 171 1.3 thorpej 172 1.3 thorpej /* 173 1.3 thorpej * Point the dvname at the actual device name that opendisk() opened. 174 1.3 thorpej */ 175 1.3 thorpej dvname = dvname_store; 176 1.1 thorpej 177 1.1 thorpej if (ioctl(fd, SCIOCIDENTIFY, &dvaddr) < 0) 178 1.1 thorpej commands = bus_commands; 179 1.1 thorpej else 180 1.1 thorpej commands = device_commands; 181 1.1 thorpej 182 1.1 thorpej /* Look up and call the command. */ 183 1.1 thorpej for (i = 0; commands[i].cmd_name != NULL; i++) 184 1.1 thorpej if (strcmp(cmdname, commands[i].cmd_name) == 0) 185 1.1 thorpej break; 186 1.1 thorpej if (commands[i].cmd_name == NULL) 187 1.12 ad errx(1, "unknown %s command: %s", 188 1.1 thorpej commands == bus_commands ? "bus" : "device", cmdname); 189 1.1 thorpej 190 1.1 thorpej (*commands[i].cmd_func)(argc, argv); 191 1.1 thorpej exit(0); 192 1.1 thorpej } 193 1.1 thorpej 194 1.33 joerg static void 195 1.26 xtraeme usage(void) 196 1.1 thorpej { 197 1.6 hubertf int i; 198 1.1 thorpej 199 1.23 jmmv fprintf(stderr, "usage: %s device command [arg [...]]\n", 200 1.11 cgd getprogname()); 201 1.7 mjl 202 1.7 mjl fprintf(stderr, " Commands pertaining to scsi devices:\n"); 203 1.42 riastrad for (i = 0; device_commands[i].cmd_name != NULL; i++) 204 1.7 mjl fprintf(stderr, "\t%s %s\n", device_commands[i].cmd_name, 205 1.6 hubertf device_commands[i].arg_names); 206 1.7 mjl fprintf(stderr, " Commands pertaining to scsi busses:\n"); 207 1.42 riastrad for (i = 0; bus_commands[i].cmd_name != NULL; i++) 208 1.7 mjl fprintf(stderr, "\t%s %s\n", bus_commands[i].cmd_name, 209 1.6 hubertf bus_commands[i].arg_names); 210 1.8 ad fprintf(stderr, " Use `any' or `all' to wildcard target or lun\n"); 211 1.42 riastrad 212 1.1 thorpej exit(1); 213 1.1 thorpej } 214 1.1 thorpej 215 1.1 thorpej /* 216 1.1 thorpej * DEVICE COMMANDS 217 1.1 thorpej */ 218 1.4 thorpej 219 1.4 thorpej /* 220 1.25 ginsbach * device_read_defect: 221 1.25 ginsbach * 222 1.25 ginsbach * Read primary and/or growth defect list in physical or block 223 1.25 ginsbach * format from a direct access device. 224 1.25 ginsbach * 225 1.25 ginsbach * XXX Does not handle very large defect lists. Needs SCSI3 12 226 1.25 ginsbach * byte READ DEFECT DATA command. 227 1.25 ginsbach */ 228 1.25 ginsbach 229 1.35 jakllsch static void print_bf_dd(union scsi_defect_descriptor *); 230 1.35 jakllsch static void print_bfif_dd(union scsi_defect_descriptor *); 231 1.35 jakllsch static void print_psf_dd(union scsi_defect_descriptor *); 232 1.25 ginsbach 233 1.35 jakllsch static void 234 1.26 xtraeme device_defects(int argc, char *argv[]) 235 1.25 ginsbach { 236 1.25 ginsbach struct scsi_read_defect_data cmd; 237 1.25 ginsbach struct scsi_read_defect_data_data *data; 238 1.25 ginsbach size_t dlen; 239 1.25 ginsbach int i, dlfmt = -1; 240 1.25 ginsbach int defects; 241 1.25 ginsbach char msg[256]; 242 1.26 xtraeme void (*pfunc)(union scsi_defect_descriptor *); 243 1.25 ginsbach #define RDD_P_G_MASK 0x18 244 1.25 ginsbach #define RDD_DLF_MASK 0x7 245 1.25 ginsbach 246 1.25 ginsbach dlen = USHRT_MAX; /* XXX - this may not be enough room 247 1.25 ginsbach * for all of the defects. 248 1.25 ginsbach */ 249 1.25 ginsbach data = malloc(dlen); 250 1.25 ginsbach if (data == NULL) 251 1.25 ginsbach errx(1, "unable to allocate defect list"); 252 1.25 ginsbach memset(data, 0, dlen); 253 1.25 ginsbach memset(&cmd, 0, sizeof(cmd)); 254 1.28 lukem defects = 0; 255 1.28 lukem pfunc = NULL; 256 1.25 ginsbach 257 1.25 ginsbach /* determine which defect list(s) to read. */ 258 1.25 ginsbach for (i = 0; i < argc; i++) { 259 1.25 ginsbach if (strncmp("primary", argv[i], 7) == 0) { 260 1.25 ginsbach cmd.flags |= RDD_PRIMARY; 261 1.25 ginsbach continue; 262 1.25 ginsbach } 263 1.25 ginsbach if (strncmp("grown", argv[i], 5) == 0) { 264 1.25 ginsbach cmd.flags |= RDD_GROWN; 265 1.25 ginsbach continue; 266 1.25 ginsbach } 267 1.25 ginsbach break; 268 1.25 ginsbach } 269 1.25 ginsbach 270 1.25 ginsbach /* no defect list sepecified, assume both. */ 271 1.25 ginsbach if ((cmd.flags & (RDD_PRIMARY|RDD_GROWN)) == 0) 272 1.25 ginsbach cmd.flags |= (RDD_PRIMARY|RDD_GROWN); 273 1.25 ginsbach 274 1.25 ginsbach /* list format option. */ 275 1.42 riastrad if (i < argc) { 276 1.25 ginsbach if (strncmp("block", argv[i], 5) == 0) { 277 1.25 ginsbach cmd.flags |= RDD_BF; 278 1.25 ginsbach dlfmt = RDD_BF; 279 1.25 ginsbach } 280 1.25 ginsbach else if (strncmp("byte", argv[i], 4) == 0) { 281 1.25 ginsbach cmd.flags |= RDD_BFIF; 282 1.25 ginsbach dlfmt = RDD_BFIF; 283 1.25 ginsbach } 284 1.25 ginsbach else if (strncmp("physical", argv[i], 4) == 0) { 285 1.25 ginsbach cmd.flags |= RDD_PSF; 286 1.25 ginsbach dlfmt = RDD_PSF; 287 1.25 ginsbach } 288 1.25 ginsbach else { 289 1.25 ginsbach usage(); 290 1.25 ginsbach } 291 1.25 ginsbach } 292 1.25 ginsbach 293 1.25 ginsbach /* 294 1.25 ginsbach * no list format specified; since block format not 295 1.25 ginsbach * recommended use physical sector format as default. 296 1.25 ginsbach */ 297 1.25 ginsbach if (dlfmt < 0) { 298 1.25 ginsbach cmd.flags |= RDD_PSF; 299 1.25 ginsbach dlfmt = RDD_PSF; 300 1.25 ginsbach } 301 1.25 ginsbach 302 1.25 ginsbach cmd.opcode = SCSI_READ_DEFECT_DATA; 303 1.25 ginsbach _lto2b(dlen, &cmd.length[0]); 304 1.25 ginsbach 305 1.25 ginsbach scsi_command(fd, &cmd, sizeof(cmd), data, dlen, 30000, SCCMD_READ); 306 1.25 ginsbach 307 1.25 ginsbach msg[0] = '\0'; 308 1.25 ginsbach 309 1.25 ginsbach /* is the defect list in the format asked for? */ 310 1.25 ginsbach if ((data->flags & RDD_DLF_MASK) != dlfmt) { 311 1.25 ginsbach strcpy(msg, "\n\tnotice:" 312 1.25 ginsbach "requested defect list format not supported by device\n\n"); 313 1.25 ginsbach dlfmt = (data->flags & RDD_DLF_MASK); 314 1.25 ginsbach } 315 1.25 ginsbach 316 1.25 ginsbach if (data->flags & RDD_PRIMARY) 317 1.25 ginsbach strcat(msg, "primary"); 318 1.25 ginsbach 319 1.25 ginsbach if (data->flags & RDD_GROWN) { 320 1.25 ginsbach if (data->flags & RDD_PRIMARY) 321 1.25 ginsbach strcat(msg, " and "); 322 1.25 ginsbach strcat(msg, "grown"); 323 1.25 ginsbach } 324 1.25 ginsbach 325 1.25 ginsbach strcat(msg, " defects"); 326 1.25 ginsbach 327 1.25 ginsbach if ((data->flags & RDD_P_G_MASK) == 0) 328 1.25 ginsbach strcat(msg, ": none reported\n"); 329 1.25 ginsbach 330 1.25 ginsbach printf("%s: scsibus%d target %d lun %d %s", 331 1.25 ginsbach dvname, dvaddr.addr.scsi.scbus, dvaddr.addr.scsi.target, 332 1.25 ginsbach dvaddr.addr.scsi.lun, msg); 333 1.25 ginsbach 334 1.25 ginsbach /* device did not return either defect list. */ 335 1.25 ginsbach if ((data->flags & RDD_P_G_MASK) == 0) 336 1.25 ginsbach return; 337 1.25 ginsbach 338 1.25 ginsbach switch (dlfmt) { 339 1.25 ginsbach case RDD_BF: 340 1.25 ginsbach defects = _2btol(data->length) / 341 1.25 ginsbach sizeof(struct scsi_defect_descriptor_bf); 342 1.25 ginsbach pfunc = print_bf_dd; 343 1.25 ginsbach strcpy(msg, "block address\n" 344 1.25 ginsbach "-------------\n"); 345 1.25 ginsbach break; 346 1.25 ginsbach case RDD_BFIF: 347 1.25 ginsbach defects = _2btol(data->length) / 348 1.25 ginsbach sizeof(struct scsi_defect_descriptor_bfif); 349 1.25 ginsbach pfunc = print_bfif_dd; 350 1.25 ginsbach strcpy(msg, " bytes from\n" 351 1.25 ginsbach "cylinder head index\n" 352 1.25 ginsbach "-------- ---- ----------\n"); 353 1.25 ginsbach break; 354 1.25 ginsbach case RDD_PSF: 355 1.25 ginsbach defects = _2btol(data->length) / 356 1.25 ginsbach sizeof(struct scsi_defect_descriptor_psf); 357 1.25 ginsbach pfunc = print_psf_dd; 358 1.25 ginsbach strcpy(msg, "cylinder head sector\n" 359 1.25 ginsbach "-------- ---- ----------\n"); 360 1.25 ginsbach break; 361 1.25 ginsbach } 362 1.25 ginsbach 363 1.25 ginsbach /* device did not return any defects. */ 364 1.25 ginsbach if (defects == 0) { 365 1.25 ginsbach printf(": none\n"); 366 1.25 ginsbach return; 367 1.25 ginsbach } 368 1.25 ginsbach 369 1.25 ginsbach printf(": %d\n", defects); 370 1.25 ginsbach 371 1.25 ginsbach /* print heading. */ 372 1.25 ginsbach printf("%s", msg); 373 1.25 ginsbach 374 1.25 ginsbach /* print defect list. */ 375 1.25 ginsbach for (i = 0 ; i < defects; i++) { 376 1.25 ginsbach pfunc(&data->defect_descriptor[i]); 377 1.25 ginsbach } 378 1.25 ginsbach 379 1.25 ginsbach free(data); 380 1.25 ginsbach return; 381 1.25 ginsbach } 382 1.25 ginsbach 383 1.25 ginsbach /* 384 1.25 ginsbach * print_bf_dd: 385 1.25 ginsbach * 386 1.25 ginsbach * Print a block format defect descriptor. 387 1.25 ginsbach */ 388 1.35 jakllsch static void 389 1.26 xtraeme print_bf_dd(union scsi_defect_descriptor *dd) 390 1.25 ginsbach { 391 1.25 ginsbach u_int32_t block; 392 1.25 ginsbach 393 1.25 ginsbach block = _4btol(dd->bf.block_address); 394 1.25 ginsbach 395 1.25 ginsbach printf("%13u\n", block); 396 1.25 ginsbach } 397 1.25 ginsbach 398 1.25 ginsbach #define DEFECTIVE_TRACK 0xffffffff 399 1.25 ginsbach 400 1.25 ginsbach /* 401 1.25 ginsbach * print_bfif_dd: 402 1.25 ginsbach * 403 1.25 ginsbach * Print a bytes from index format defect descriptor. 404 1.25 ginsbach */ 405 1.35 jakllsch static void 406 1.26 xtraeme print_bfif_dd(union scsi_defect_descriptor *dd) 407 1.25 ginsbach { 408 1.25 ginsbach u_int32_t cylinder; 409 1.25 ginsbach u_int32_t head; 410 1.25 ginsbach u_int32_t bytes_from_index; 411 1.25 ginsbach 412 1.25 ginsbach cylinder = _3btol(dd->bfif.cylinder); 413 1.25 ginsbach head = dd->bfif.head; 414 1.25 ginsbach bytes_from_index = _4btol(dd->bfif.bytes_from_index); 415 1.25 ginsbach 416 1.25 ginsbach printf("%8u %4u ", cylinder, head); 417 1.25 ginsbach 418 1.25 ginsbach if (bytes_from_index == DEFECTIVE_TRACK) 419 1.25 ginsbach printf("entire track defective\n"); 420 1.25 ginsbach else 421 1.25 ginsbach printf("%10u\n", bytes_from_index); 422 1.25 ginsbach } 423 1.25 ginsbach 424 1.25 ginsbach /* 425 1.25 ginsbach * print_psf_dd: 426 1.25 ginsbach * 427 1.25 ginsbach * Print a physical sector format defect descriptor. 428 1.25 ginsbach */ 429 1.35 jakllsch static void 430 1.26 xtraeme print_psf_dd(union scsi_defect_descriptor *dd) 431 1.25 ginsbach { 432 1.25 ginsbach u_int32_t cylinder; 433 1.25 ginsbach u_int32_t head; 434 1.25 ginsbach u_int32_t sector; 435 1.25 ginsbach 436 1.25 ginsbach cylinder = _3btol(dd->psf.cylinder); 437 1.25 ginsbach head = dd->psf.head; 438 1.25 ginsbach sector = _4btol(dd->psf.sector); 439 1.25 ginsbach 440 1.25 ginsbach printf("%8u %4u ", cylinder, head); 441 1.25 ginsbach 442 1.25 ginsbach if (sector == DEFECTIVE_TRACK) 443 1.25 ginsbach printf("entire track defective\n"); 444 1.25 ginsbach else 445 1.25 ginsbach printf("%10u\n", sector); 446 1.25 ginsbach } 447 1.25 ginsbach 448 1.25 ginsbach /* 449 1.4 thorpej * device_format: 450 1.4 thorpej * 451 1.4 thorpej * Format a direct access device. 452 1.4 thorpej */ 453 1.35 jakllsch static void 454 1.26 xtraeme device_format(int argc, char *argv[]) 455 1.4 thorpej { 456 1.16 mjacob u_int32_t blksize; 457 1.16 mjacob int i, j, immediate; 458 1.16 mjacob #define PC (65536/10) 459 1.16 mjacob static int complete[] = { 460 1.16 mjacob PC*1, PC*2, PC*3, PC*4, PC*5, PC*6, PC*7, PC*8, PC*9, 65536 461 1.16 mjacob }; 462 1.16 mjacob char *cp, buffer[64]; 463 1.27 thorpej struct scsi_sense_data sense; 464 1.4 thorpej struct scsi_format_unit cmd; 465 1.4 thorpej struct { 466 1.16 mjacob struct scsi_format_unit_defect_list_header header; 467 1.16 mjacob /* optional initialization pattern */ 468 1.16 mjacob /* optional defect list */ 469 1.16 mjacob } dfl; 470 1.16 mjacob struct { 471 1.27 thorpej struct scsi_mode_parameter_header_6 header; 472 1.27 thorpej struct scsi_general_block_descriptor blk_desc; 473 1.4 thorpej struct page_disk_format format_page; 474 1.16 mjacob } mode_page; 475 1.16 mjacob struct { 476 1.27 thorpej struct scsi_mode_parameter_header_6 header; 477 1.27 thorpej struct scsi_general_block_descriptor blk_desc; 478 1.16 mjacob } data_select; 479 1.4 thorpej 480 1.16 mjacob /* Blocksize is an optional argument. */ 481 1.16 mjacob if (argc > 2) 482 1.6 hubertf usage(); 483 1.4 thorpej 484 1.4 thorpej /* 485 1.16 mjacob * Loop doing Request Sense to clear any pending Unit Attention. 486 1.16 mjacob * 487 1.16 mjacob * Multiple conditions may exist on the drive which are returned 488 1.16 mjacob * in priority order. 489 1.16 mjacob */ 490 1.16 mjacob for (i = 0; i < 8; i++) { 491 1.16 mjacob scsi_request_sense(fd, &sense, sizeof (sense)); 492 1.27 thorpej if ((j = SSD_SENSE_KEY(sense.flags)) == SKEY_NO_SENSE) 493 1.16 mjacob break; 494 1.16 mjacob } 495 1.16 mjacob /* 496 1.16 mjacob * Make sure we cleared any pending Unit Attention 497 1.16 mjacob */ 498 1.16 mjacob if (j != SKEY_NO_SENSE) { 499 1.16 mjacob cp = scsi_decode_sense((const unsigned char *) &sense, 2, 500 1.16 mjacob buffer, sizeof (buffer)); 501 1.17 grant errx(1, "failed to clean Unit Attention: %s", cp); 502 1.16 mjacob } 503 1.16 mjacob 504 1.16 mjacob /* 505 1.4 thorpej * Get the DISK FORMAT mode page. SCSI-2 recommends specifying the 506 1.4 thorpej * interleave read from this page in the FORMAT UNIT command. 507 1.4 thorpej */ 508 1.16 mjacob scsi_mode_sense(fd, 0x03, 0x00, &mode_page, sizeof(mode_page)); 509 1.16 mjacob 510 1.16 mjacob j = (mode_page.format_page.bytes_s[0] << 8) | 511 1.16 mjacob (mode_page.format_page.bytes_s[1]); 512 1.16 mjacob 513 1.16 mjacob if (j != DEV_BSIZE) 514 1.32 joerg printf("current disk sector size: %d\n", j); 515 1.4 thorpej 516 1.4 thorpej memset(&cmd, 0, sizeof(cmd)); 517 1.4 thorpej 518 1.4 thorpej cmd.opcode = SCSI_FORMAT_UNIT; 519 1.16 mjacob memcpy(cmd.interleave, mode_page.format_page.interleave, 520 1.4 thorpej sizeof(cmd.interleave)); 521 1.4 thorpej 522 1.16 mjacob /* 523 1.16 mjacob * The blocksize on the device is only changed if the user 524 1.16 mjacob * specified a new blocksize. If not specified the blocksize 525 1.16 mjacob * used for the device will be the Default value in the device. 526 1.16 mjacob * We don't specify the number of blocks since the format 527 1.16 mjacob * command will always reformat the entire drive. Also by 528 1.16 mjacob * not specifying a block count the drive will reset the 529 1.16 mjacob * block count to the maximum available after the format 530 1.16 mjacob * completes if the blocksize was changed in the format. 531 1.16 mjacob * Finally, the new disk geometry will not but updated on 532 1.16 mjacob * the drive in permanent storage until _AFTER_ the format 533 1.16 mjacob * completes successfully. 534 1.16 mjacob */ 535 1.16 mjacob if (argc > 0) { 536 1.16 mjacob blksize = strtoul(argv[0], &cp, 10); 537 1.16 mjacob if (*cp != '\0') 538 1.17 grant errx(1, "invalid block size: %s", argv[0]); 539 1.16 mjacob 540 1.16 mjacob memset(&data_select, 0, sizeof(data_select)); 541 1.16 mjacob 542 1.27 thorpej data_select.header.blk_desc_len = 543 1.27 thorpej sizeof(struct scsi_general_block_descriptor); 544 1.16 mjacob /* 545 1.16 mjacob * blklen in desc is 3 bytes with a leading reserved byte 546 1.16 mjacob */ 547 1.16 mjacob _lto4b(blksize, &data_select.blk_desc.reserved); 548 1.16 mjacob 549 1.16 mjacob /* 550 1.16 mjacob * Issue Mode Select to modify the device blocksize to be 551 1.16 mjacob * used on the Format. The modified device geometry will 552 1.16 mjacob * be stored as Current and Saved Page 3 parameters when 553 1.16 mjacob * the Format completes. 554 1.16 mjacob */ 555 1.16 mjacob scsi_mode_select(fd, 0, &data_select, sizeof(data_select)); 556 1.16 mjacob 557 1.16 mjacob /* 558 1.16 mjacob * Since user specified a specific block size make sure it 559 1.16 mjacob * gets stored in the device when the format completes. 560 1.16 mjacob * 561 1.16 mjacob * Also scrub the defect list back to the manufacturers 562 1.16 mjacob * original. 563 1.16 mjacob */ 564 1.16 mjacob cmd.flags = SFU_CMPLST | SFU_FMTDATA; 565 1.16 mjacob } 566 1.16 mjacob 567 1.16 mjacob memset(&dfl, 0, sizeof(dfl)); 568 1.4 thorpej 569 1.16 mjacob if (argc > 1 && strncmp(argv[1], "imm", 3) == 0) { 570 1.16 mjacob /* 571 1.16 mjacob * Signal target for an immediate return from Format. 572 1.16 mjacob * 573 1.16 mjacob * We'll poll for completion status. 574 1.16 mjacob */ 575 1.16 mjacob dfl.header.flags = DLH_IMMED; 576 1.16 mjacob immediate = 1; 577 1.16 mjacob } else { 578 1.16 mjacob immediate = 0; 579 1.16 mjacob } 580 1.16 mjacob 581 1.16 mjacob scsi_command(fd, &cmd, sizeof(cmd), &dfl, sizeof(dfl), 582 1.37 jakllsch 8 * 60 * 60 * 1000, SCCMD_WRITE); 583 1.16 mjacob 584 1.16 mjacob /* 585 1.16 mjacob * Poll device for completion of Format 586 1.16 mjacob */ 587 1.16 mjacob if (immediate) { 588 1.16 mjacob i = 0; 589 1.16 mjacob printf("formatting."); 590 1.16 mjacob fflush(stdout); 591 1.16 mjacob do { 592 1.16 mjacob scsireq_t req; 593 1.27 thorpej struct scsi_test_unit_ready tcmd; 594 1.16 mjacob 595 1.36 jakllsch memset(&tcmd, 0, sizeof(tcmd)); 596 1.27 thorpej tcmd.opcode = SCSI_TEST_UNIT_READY; 597 1.16 mjacob 598 1.16 mjacob memset(&req, 0, sizeof(req)); 599 1.16 mjacob memcpy(req.cmd, &tcmd, 6); 600 1.16 mjacob req.cmdlen = 6; 601 1.16 mjacob req.timeout = 10000; 602 1.16 mjacob req.senselen = SENSEBUFLEN; 603 1.16 mjacob 604 1.16 mjacob if (ioctl(fd, SCIOCCOMMAND, &req) == -1) { 605 1.16 mjacob err(1, "SCIOCCOMMAND"); 606 1.16 mjacob } 607 1.16 mjacob 608 1.16 mjacob if (req.retsts == SCCMD_OK) { 609 1.16 mjacob break; 610 1.16 mjacob } else if (req.retsts == SCCMD_TIMEOUT) { 611 1.16 mjacob fprintf(stderr, "%s: SCSI command timed out", 612 1.16 mjacob dvname); 613 1.16 mjacob break; 614 1.16 mjacob } else if (req.retsts == SCCMD_BUSY) { 615 1.16 mjacob fprintf(stderr, "%s: device is busy", 616 1.16 mjacob dvname); 617 1.16 mjacob break; 618 1.16 mjacob } else if (req.retsts != SCCMD_SENSE) { 619 1.16 mjacob fprintf(stderr, 620 1.16 mjacob "%s: device had unknown status %x", dvname, 621 1.16 mjacob req.retsts); 622 1.16 mjacob break; 623 1.16 mjacob } 624 1.30 christos memcpy(&sense, req.sense, sizeof(sense)); 625 1.27 thorpej if (sense.sks.sks_bytes[0] & SSD_SKSV) { 626 1.27 thorpej j = (sense.sks.sks_bytes[1] << 8) | 627 1.27 thorpej (sense.sks.sks_bytes[2]); 628 1.16 mjacob if (j >= complete[i]) { 629 1.16 mjacob printf(".%d0%%.", ++i); 630 1.16 mjacob fflush(stdout); 631 1.16 mjacob } 632 1.16 mjacob } 633 1.16 mjacob sleep(10); 634 1.27 thorpej } while (SSD_SENSE_KEY(sense.flags) == SKEY_NOT_READY); 635 1.16 mjacob printf(".100%%..done.\n"); 636 1.16 mjacob } 637 1.4 thorpej return; 638 1.4 thorpej } 639 1.1 thorpej 640 1.41 mlelstv static void 641 1.41 mlelstv print_designator(const char *pre, struct scsipi_inquiry_evpd_device_id *did) 642 1.41 mlelstv { 643 1.41 mlelstv char buf[252 * 4 + 1]; 644 1.41 mlelstv unsigned assoc, proto, code, type; 645 1.41 mlelstv static const char *typestr[] = { 646 1.41 mlelstv "vendor", 647 1.41 mlelstv "t10", 648 1.41 mlelstv "eui64", 649 1.41 mlelstv "naa", 650 1.41 mlelstv "target port", 651 1.41 mlelstv "port group", 652 1.41 mlelstv "lun group", 653 1.41 mlelstv "md5", 654 1.41 mlelstv "scsi", 655 1.41 mlelstv "res9", 656 1.41 mlelstv "res10", 657 1.41 mlelstv "res11", 658 1.41 mlelstv "res12", 659 1.41 mlelstv "res13", 660 1.41 mlelstv "res14", 661 1.41 mlelstv "res15" 662 1.41 mlelstv }; 663 1.41 mlelstv static const char *assocstr[] = { 664 1.41 mlelstv "lun", 665 1.41 mlelstv "port", 666 1.41 mlelstv "target", 667 1.41 mlelstv "reserved" 668 1.41 mlelstv }; 669 1.41 mlelstv static const char *protostr[] = { 670 1.41 mlelstv "fibre channel", 671 1.41 mlelstv "obsolete", 672 1.41 mlelstv "ssa", 673 1.41 mlelstv "ieee1394", 674 1.41 mlelstv "rdma", 675 1.41 mlelstv "iSCSI", 676 1.41 mlelstv "SAS" 677 1.41 mlelstv }; 678 1.41 mlelstv const unsigned maxproto = __arraycount(protostr) - 1; 679 1.41 mlelstv const unsigned isbinary = 680 1.41 mlelstv __SHIFTOUT(SINQ_DEVICE_ID_CODESET_BINARY, SINQ_DEVICE_ID_CODESET); 681 1.41 mlelstv unsigned k; 682 1.41 mlelstv 683 1.41 mlelstv assoc = __SHIFTOUT(did->flags, SINQ_DEVICE_ID_ASSOCIATION); 684 1.41 mlelstv proto = __SHIFTOUT(did->pc, SINQ_DEVICE_ID_PROTOCOL); 685 1.41 mlelstv code = __SHIFTOUT(did->pc, SINQ_DEVICE_ID_CODESET); 686 1.41 mlelstv type = __SHIFTOUT(did->flags, SINQ_DEVICE_ID_TYPE); 687 1.41 mlelstv 688 1.41 mlelstv printf("%s%s", pre, assocstr[assoc]); 689 1.41 mlelstv if (did->flags & SINQ_DEVICE_ID_PIV) { 690 1.41 mlelstv if (proto > maxproto) 691 1.41 mlelstv printf(" proto%u", proto); 692 1.41 mlelstv else 693 1.41 mlelstv printf(" %s", protostr[proto]); 694 1.41 mlelstv } 695 1.41 mlelstv printf(" %s: ", typestr[type]); 696 1.41 mlelstv 697 1.41 mlelstv if (code == isbinary) { 698 1.42 riastrad for (k = 0; k < did->designator_length; k++) { 699 1.41 mlelstv printf("%02x", did->designator[k]); 700 1.41 mlelstv } 701 1.41 mlelstv printf("\n"); 702 1.41 mlelstv } else { 703 1.41 mlelstv scsi_strvis(buf, sizeof(buf), (char *)did->designator, 704 1.41 mlelstv did->designator_length); 705 1.41 mlelstv printf("%s\n", buf); 706 1.41 mlelstv } 707 1.41 mlelstv } 708 1.41 mlelstv 709 1.1 thorpej /* 710 1.1 thorpej * device_identify: 711 1.1 thorpej * 712 1.38 snj * Display the identity of the device, including its SCSI bus, 713 1.38 snj * target, lun, and its vendor/product/revision information. 714 1.41 mlelstv * Optionally query and display vpd identification data. 715 1.1 thorpej */ 716 1.35 jakllsch static void 717 1.26 xtraeme device_identify(int argc, char *argv[]) 718 1.1 thorpej { 719 1.1 thorpej struct scsipi_inquiry_data inqbuf; 720 1.41 mlelstv struct { 721 1.41 mlelstv struct scsipi_inquiry_evpd_header h; 722 1.41 mlelstv uint8_t d[255 - sizeof(struct scsipi_inquiry_evpd_header)]; 723 1.41 mlelstv } evpdbuf; 724 1.1 thorpej struct scsipi_inquiry cmd; 725 1.41 mlelstv unsigned len, rlen; 726 1.41 mlelstv struct scsipi_inquiry_evpd_serial *ser; 727 1.41 mlelstv struct scsipi_inquiry_evpd_device_id *did; 728 1.41 mlelstv int has_serial; 729 1.41 mlelstv int has_device_id; 730 1.41 mlelstv bool getvpd = false; 731 1.41 mlelstv int i; 732 1.1 thorpej 733 1.1 thorpej /* x4 in case every character is escaped, +1 for NUL. */ 734 1.1 thorpej char vendor[(sizeof(inqbuf.vendor) * 4) + 1], 735 1.1 thorpej product[(sizeof(inqbuf.product) * 4) + 1], 736 1.41 mlelstv revision[(sizeof(inqbuf.revision) * 4) + 1], 737 1.41 mlelstv ident[252 * 4 + 1]; 738 1.1 thorpej 739 1.41 mlelstv /* Check optional arguments */ 740 1.41 mlelstv for (i = 0; i < argc; i++) { 741 1.41 mlelstv if (strncmp("vpd", argv[i], 3) == 0) { 742 1.41 mlelstv getvpd = true; 743 1.41 mlelstv continue; 744 1.41 mlelstv } 745 1.6 hubertf usage(); 746 1.41 mlelstv } 747 1.1 thorpej 748 1.1 thorpej memset(&cmd, 0, sizeof(cmd)); 749 1.1 thorpej memset(&inqbuf, 0, sizeof(inqbuf)); 750 1.1 thorpej 751 1.1 thorpej cmd.opcode = INQUIRY; 752 1.1 thorpej cmd.length = sizeof(inqbuf); 753 1.1 thorpej 754 1.1 thorpej scsi_command(fd, &cmd, sizeof(cmd), &inqbuf, sizeof(inqbuf), 755 1.1 thorpej 10000, SCCMD_READ); 756 1.1 thorpej 757 1.1 thorpej scsi_strvis(vendor, sizeof(vendor), inqbuf.vendor, 758 1.1 thorpej sizeof(inqbuf.vendor)); 759 1.1 thorpej scsi_strvis(product, sizeof(product), inqbuf.product, 760 1.1 thorpej sizeof(inqbuf.product)); 761 1.1 thorpej scsi_strvis(revision, sizeof(revision), inqbuf.revision, 762 1.1 thorpej sizeof(inqbuf.revision)); 763 1.1 thorpej 764 1.1 thorpej printf("%s: scsibus%d target %d lun %d <%s, %s, %s>\n", 765 1.1 thorpej dvname, dvaddr.addr.scsi.scbus, dvaddr.addr.scsi.target, 766 1.1 thorpej dvaddr.addr.scsi.lun, vendor, product, revision); 767 1.1 thorpej 768 1.41 mlelstv if (!getvpd) 769 1.41 mlelstv return; 770 1.41 mlelstv 771 1.41 mlelstv cmd.byte2 |= SINQ_EVPD; 772 1.41 mlelstv cmd.pagecode = SINQ_VPD_PAGES; 773 1.41 mlelstv 774 1.41 mlelstv scsi_command(fd, &cmd, sizeof(cmd), &evpdbuf, sizeof(evpdbuf), 775 1.41 mlelstv 10000, SCCMD_READ); 776 1.41 mlelstv 777 1.41 mlelstv len = be16dec(evpdbuf.h.length); 778 1.41 mlelstv if (len > sizeof(evpdbuf.d)) 779 1.41 mlelstv len = 0; 780 1.41 mlelstv 781 1.41 mlelstv has_serial = memchr(evpdbuf.d, SINQ_VPD_SERIAL, len) != NULL; 782 1.41 mlelstv has_device_id = memchr(evpdbuf.d, SINQ_VPD_DEVICE_ID, len) != NULL; 783 1.41 mlelstv 784 1.41 mlelstv if (has_serial) { 785 1.41 mlelstv cmd.byte2 |= SINQ_EVPD; 786 1.41 mlelstv cmd.pagecode = SINQ_VPD_SERIAL; 787 1.41 mlelstv 788 1.41 mlelstv scsi_command(fd, &cmd, sizeof(cmd), &evpdbuf, sizeof(evpdbuf), 789 1.41 mlelstv 10000, SCCMD_READ); 790 1.41 mlelstv 791 1.41 mlelstv len = be16dec(evpdbuf.h.length); 792 1.41 mlelstv if (len > sizeof(evpdbuf.d)) 793 1.41 mlelstv len = 0; 794 1.41 mlelstv 795 1.41 mlelstv ser = (struct scsipi_inquiry_evpd_serial *)&evpdbuf.d; 796 1.42 riastrad scsi_strvis(ident, sizeof(ident), (char *)ser->serial_number, 797 1.42 riastrad len); 798 1.41 mlelstv printf("VPD Serial:\n"); 799 1.41 mlelstv printf("\t%s\n", ident); 800 1.41 mlelstv } 801 1.41 mlelstv 802 1.41 mlelstv if (has_device_id) { 803 1.41 mlelstv cmd.byte2 |= SINQ_EVPD; 804 1.41 mlelstv cmd.pagecode = SINQ_VPD_DEVICE_ID; 805 1.41 mlelstv 806 1.41 mlelstv scsi_command(fd, &cmd, sizeof(cmd), &evpdbuf, sizeof(evpdbuf), 807 1.41 mlelstv 10000, SCCMD_READ); 808 1.41 mlelstv 809 1.41 mlelstv len = be16dec(evpdbuf.h.length); 810 1.41 mlelstv if (len > sizeof(evpdbuf.d)) 811 1.41 mlelstv len = 0; 812 1.41 mlelstv 813 1.41 mlelstv printf("VPD Device IDs:\n"); 814 1.41 mlelstv 815 1.42 riastrad for (unsigned off = 0; off < len - sizeof(*did); off += rlen) { 816 1.42 riastrad void *p = &evpdbuf.d[off]; 817 1.42 riastrad did = (struct scsipi_inquiry_evpd_device_id *)p; 818 1.41 mlelstv rlen = sizeof(*did) + did->designator_length - 1; 819 1.41 mlelstv if (off + rlen > len) 820 1.41 mlelstv break; 821 1.41 mlelstv 822 1.41 mlelstv print_designator("\t", did); 823 1.41 mlelstv } 824 1.41 mlelstv } 825 1.41 mlelstv 826 1.1 thorpej return; 827 1.1 thorpej } 828 1.1 thorpej 829 1.1 thorpej /* 830 1.1 thorpej * device_reassign: 831 1.1 thorpej * 832 1.1 thorpej * Reassign bad blocks on a direct access device. 833 1.1 thorpej */ 834 1.35 jakllsch static void 835 1.26 xtraeme device_reassign(int argc, char *argv[]) 836 1.1 thorpej { 837 1.1 thorpej struct scsi_reassign_blocks cmd; 838 1.1 thorpej struct scsi_reassign_blocks_data *data; 839 1.1 thorpej size_t dlen; 840 1.1 thorpej u_int32_t blkno; 841 1.1 thorpej int i; 842 1.1 thorpej char *cp; 843 1.1 thorpej 844 1.1 thorpej /* We get a list of block numbers. */ 845 1.1 thorpej if (argc < 1) 846 1.6 hubertf usage(); 847 1.1 thorpej 848 1.1 thorpej /* 849 1.1 thorpej * Allocate the reassign blocks descriptor. The 4 comes from the 850 1.1 thorpej * size of the block address in the defect descriptor. 851 1.1 thorpej */ 852 1.1 thorpej dlen = sizeof(struct scsi_reassign_blocks_data) + ((argc - 1) * 4); 853 1.1 thorpej data = malloc(dlen); 854 1.1 thorpej if (data == NULL) 855 1.1 thorpej errx(1, "unable to allocate defect descriptor"); 856 1.1 thorpej memset(data, 0, dlen); 857 1.1 thorpej 858 1.1 thorpej cmd.opcode = SCSI_REASSIGN_BLOCKS; 859 1.9 mycroft cmd.byte2 = 0; 860 1.9 mycroft cmd.unused[0] = 0; 861 1.9 mycroft cmd.unused[1] = 0; 862 1.9 mycroft cmd.unused[2] = 0; 863 1.9 mycroft cmd.control = 0; 864 1.1 thorpej 865 1.1 thorpej /* Defect descriptor length. */ 866 1.9 mycroft _lto2b(argc * 4, data->length); 867 1.1 thorpej 868 1.1 thorpej /* Build the defect descriptor list. */ 869 1.1 thorpej for (i = 0; i < argc; i++) { 870 1.1 thorpej blkno = strtoul(argv[i], &cp, 10); 871 1.1 thorpej if (*cp != '\0') 872 1.12 ad errx(1, "invalid block number: %s", argv[i]); 873 1.9 mycroft _lto4b(blkno, data->defect_descriptor[i].dlbaddr); 874 1.1 thorpej } 875 1.1 thorpej 876 1.1 thorpej scsi_command(fd, &cmd, sizeof(cmd), data, dlen, 30000, SCCMD_WRITE); 877 1.1 thorpej 878 1.1 thorpej free(data); 879 1.1 thorpej return; 880 1.1 thorpej } 881 1.1 thorpej 882 1.1 thorpej /* 883 1.16 mjacob * device_release: 884 1.16 mjacob * 885 1.29 bouyer * Issue a RELEASE command to a SCSI device. 886 1.16 mjacob */ 887 1.16 mjacob #ifndef SCSI_RELEASE 888 1.16 mjacob #define SCSI_RELEASE 0x17 889 1.16 mjacob #endif 890 1.35 jakllsch static void 891 1.26 xtraeme device_release(int argc, char *argv[]) 892 1.16 mjacob { 893 1.27 thorpej struct scsi_test_unit_ready cmd; /* close enough */ 894 1.16 mjacob 895 1.16 mjacob /* No arguments. */ 896 1.16 mjacob if (argc != 0) 897 1.16 mjacob usage(); 898 1.16 mjacob 899 1.16 mjacob memset(&cmd, 0, sizeof(cmd)); 900 1.16 mjacob 901 1.16 mjacob cmd.opcode = SCSI_RELEASE; 902 1.16 mjacob 903 1.16 mjacob scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 904 1.16 mjacob 905 1.16 mjacob return; 906 1.16 mjacob } 907 1.16 mjacob 908 1.16 mjacob /* 909 1.16 mjacob * device_reserve: 910 1.16 mjacob * 911 1.29 bouyer * Issue a RESERVE command to a SCSI device. 912 1.16 mjacob */ 913 1.16 mjacob #ifndef SCSI_RESERVE 914 1.16 mjacob #define SCSI_RESERVE 0x16 915 1.16 mjacob #endif 916 1.35 jakllsch static void 917 1.26 xtraeme device_reserve(int argc, char *argv[]) 918 1.16 mjacob { 919 1.27 thorpej struct scsi_test_unit_ready cmd; /* close enough */ 920 1.16 mjacob 921 1.16 mjacob /* No arguments. */ 922 1.16 mjacob if (argc != 0) 923 1.16 mjacob usage(); 924 1.16 mjacob 925 1.16 mjacob memset(&cmd, 0, sizeof(cmd)); 926 1.16 mjacob 927 1.16 mjacob cmd.opcode = SCSI_RESERVE; 928 1.16 mjacob 929 1.16 mjacob scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 930 1.16 mjacob 931 1.16 mjacob return; 932 1.16 mjacob } 933 1.16 mjacob 934 1.16 mjacob /* 935 1.1 thorpej * device_reset: 936 1.1 thorpej * 937 1.1 thorpej * Issue a reset to a SCSI device. 938 1.1 thorpej */ 939 1.35 jakllsch static void 940 1.26 xtraeme device_reset(int argc, char *argv[]) 941 1.1 thorpej { 942 1.1 thorpej 943 1.1 thorpej /* No arguments. */ 944 1.1 thorpej if (argc != 0) 945 1.6 hubertf usage(); 946 1.1 thorpej 947 1.1 thorpej if (ioctl(fd, SCIOCRESET, NULL) != 0) 948 1.1 thorpej err(1, "SCIOCRESET"); 949 1.19 petrov 950 1.19 petrov return; 951 1.19 petrov } 952 1.19 petrov 953 1.19 petrov /* 954 1.19 petrov * device_debug: 955 1.19 petrov * 956 1.19 petrov * Set debug level to a SCSI device. 957 1.19 petrov * scsipi will print anything iff SCSIPI_DEBUG set in config. 958 1.19 petrov */ 959 1.35 jakllsch static void 960 1.26 xtraeme device_debug(int argc, char *argv[]) 961 1.19 petrov { 962 1.19 petrov int lvl; 963 1.19 petrov 964 1.19 petrov if (argc < 1) 965 1.19 petrov usage(); 966 1.19 petrov 967 1.19 petrov lvl = atoi(argv[0]); 968 1.19 petrov 969 1.19 petrov if (ioctl(fd, SCIOCDEBUG, &lvl) != 0) 970 1.19 petrov err(1, "SCIOCDEBUG"); 971 1.1 thorpej 972 1.1 thorpej return; 973 1.1 thorpej } 974 1.1 thorpej 975 1.1 thorpej /* 976 1.18 thorpej * device_getcache: 977 1.18 thorpej * 978 1.18 thorpej * Get the caching parameters for a SCSI disk. 979 1.1 thorpej */ 980 1.35 jakllsch static void 981 1.26 xtraeme device_getcache(int argc, char *argv[]) 982 1.18 thorpej { 983 1.18 thorpej struct { 984 1.27 thorpej struct scsi_mode_parameter_header_6 header; 985 1.27 thorpej struct scsi_general_block_descriptor blk_desc; 986 1.18 thorpej struct page_caching caching_params; 987 1.18 thorpej } data; 988 1.18 thorpej 989 1.18 thorpej /* No arguments. */ 990 1.18 thorpej if (argc != 0) 991 1.18 thorpej usage(); 992 1.18 thorpej 993 1.18 thorpej scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data)); 994 1.18 thorpej 995 1.18 thorpej if ((data.caching_params.flags & (CACHING_RCD|CACHING_WCE)) == 996 1.18 thorpej CACHING_RCD) 997 1.18 thorpej printf("%s: no caches enabled\n", dvname); 998 1.18 thorpej else { 999 1.18 thorpej printf("%s: read cache %senabled\n", dvname, 1000 1.18 thorpej (data.caching_params.flags & CACHING_RCD) ? "not " : ""); 1001 1.18 thorpej printf("%s: write-back cache %senabled\n", dvname, 1002 1.18 thorpej (data.caching_params.flags & CACHING_WCE) ? "" : "not "); 1003 1.18 thorpej } 1004 1.18 thorpej printf("%s: caching parameters are %ssavable\n", dvname, 1005 1.18 thorpej (data.caching_params.pg_code & PGCODE_PS) ? "" : "not "); 1006 1.18 thorpej } 1007 1.1 thorpej 1008 1.1 thorpej /* 1009 1.18 thorpej * device_setcache: 1010 1.1 thorpej * 1011 1.18 thorpej * Set cache enables for a SCSI disk. 1012 1.1 thorpej */ 1013 1.35 jakllsch static void 1014 1.26 xtraeme device_setcache(int argc, char *argv[]) 1015 1.1 thorpej { 1016 1.18 thorpej struct { 1017 1.27 thorpej struct scsi_mode_parameter_header_6 header; 1018 1.27 thorpej struct scsi_general_block_descriptor blk_desc; 1019 1.18 thorpej struct page_caching caching_params; 1020 1.18 thorpej } data; 1021 1.18 thorpej int dlen; 1022 1.18 thorpej u_int8_t flags, byte2; 1023 1.18 thorpej 1024 1.18 thorpej if (argc > 2 || argc == 0) 1025 1.18 thorpej usage(); 1026 1.18 thorpej 1027 1.28 lukem flags = 0; 1028 1.28 lukem byte2 = 0; 1029 1.18 thorpej if (strcmp(argv[0], "none") == 0) 1030 1.18 thorpej flags = CACHING_RCD; 1031 1.18 thorpej else if (strcmp(argv[0], "r") == 0) 1032 1.18 thorpej flags = 0; 1033 1.18 thorpej else if (strcmp(argv[0], "w") == 0) 1034 1.18 thorpej flags = CACHING_RCD|CACHING_WCE; 1035 1.18 thorpej else if (strcmp(argv[0], "rw") == 0) 1036 1.18 thorpej flags = CACHING_WCE; 1037 1.18 thorpej else 1038 1.18 thorpej usage(); 1039 1.18 thorpej 1040 1.18 thorpej if (argc == 2) { 1041 1.18 thorpej if (strcmp(argv[1], "save") == 0) 1042 1.18 thorpej byte2 = SMS_SP; 1043 1.18 thorpej else 1044 1.18 thorpej usage(); 1045 1.18 thorpej } 1046 1.18 thorpej 1047 1.18 thorpej scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data)); 1048 1.18 thorpej 1049 1.18 thorpej data.caching_params.pg_code &= PGCODE_MASK; 1050 1.18 thorpej data.caching_params.flags = 1051 1.18 thorpej (data.caching_params.flags & ~(CACHING_RCD|CACHING_WCE)) | flags; 1052 1.1 thorpej 1053 1.18 thorpej data.caching_params.cache_segment_size[0] = 0; 1054 1.18 thorpej data.caching_params.cache_segment_size[1] = 0; 1055 1.18 thorpej 1056 1.18 thorpej data.header.data_length = 0; 1057 1.1 thorpej 1058 1.18 thorpej dlen = sizeof(data.header) + sizeof(data.blk_desc) + 2 + 1059 1.18 thorpej data.caching_params.pg_length; 1060 1.1 thorpej 1061 1.18 thorpej scsi_mode_select(fd, byte2, &data, dlen); 1062 1.21 mycroft } 1063 1.21 mycroft 1064 1.21 mycroft /* 1065 1.21 mycroft * device_flushcache: 1066 1.21 mycroft * 1067 1.29 bouyer * Issue a FLUSH CACHE command to a SCSI device. 1068 1.21 mycroft */ 1069 1.21 mycroft #ifndef SCSI_FLUSHCACHE 1070 1.21 mycroft #define SCSI_FLUSHCACHE 0x35 1071 1.21 mycroft #endif 1072 1.35 jakllsch static void 1073 1.26 xtraeme device_flushcache(int argc, char *argv[]) 1074 1.21 mycroft { 1075 1.27 thorpej struct scsi_test_unit_ready cmd; /* close enough */ 1076 1.21 mycroft 1077 1.21 mycroft /* No arguments. */ 1078 1.21 mycroft if (argc != 0) 1079 1.21 mycroft usage(); 1080 1.21 mycroft 1081 1.21 mycroft memset(&cmd, 0, sizeof(cmd)); 1082 1.21 mycroft 1083 1.21 mycroft cmd.opcode = SCSI_FLUSHCACHE; 1084 1.22 mycroft 1085 1.22 mycroft scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 1086 1.22 mycroft 1087 1.22 mycroft return; 1088 1.22 mycroft } 1089 1.22 mycroft 1090 1.22 mycroft /* 1091 1.29 bouyer * device_setspeed: 1092 1.29 bouyer * 1093 1.29 bouyer * Set rotation speed to a CD/DVD drive. 1094 1.29 bouyer */ 1095 1.35 jakllsch static void 1096 1.29 bouyer device_setspeed(int argc, char *argv[]) 1097 1.29 bouyer { 1098 1.29 bouyer u_char cmd[11]; 1099 1.29 bouyer u_char pd[28]; 1100 1.29 bouyer u_int32_t speed; 1101 1.29 bouyer 1102 1.29 bouyer if (argc != 1) 1103 1.29 bouyer usage(); 1104 1.29 bouyer 1105 1.29 bouyer speed = atoi(argv[0]) * 177; 1106 1.29 bouyer 1107 1.29 bouyer memset(&pd, 0, sizeof(pd)); 1108 1.29 bouyer if (speed == 0) 1109 1.29 bouyer pd[0] = 4; /* restore drive defaults */ 1110 1.29 bouyer pd[8] = 0xff; 1111 1.29 bouyer pd[9] = 0xff; 1112 1.29 bouyer pd[10] = 0xff; 1113 1.29 bouyer pd[11] = 0xff; 1114 1.29 bouyer pd[12] = pd[20] = (speed >> 24) & 0xff; 1115 1.29 bouyer pd[13] = pd[21] = (speed >> 16) & 0xff; 1116 1.29 bouyer pd[14] = pd[22] = (speed >> 8) & 0xff; 1117 1.29 bouyer pd[15] = pd[23] = speed & 0xff; 1118 1.29 bouyer pd[18] = pd[26] = 1000 >> 8; 1119 1.29 bouyer pd[19] = pd[27] = 1000 & 0xff; 1120 1.29 bouyer 1121 1.29 bouyer memset(&cmd, 0, sizeof(cmd)); 1122 1.29 bouyer cmd[0] = 0xb6; 1123 1.29 bouyer cmd[10] = sizeof(pd); 1124 1.29 bouyer 1125 1.29 bouyer scsi_command(fd, &cmd, sizeof(cmd), pd, sizeof(pd), 10000, SCCMD_WRITE); 1126 1.29 bouyer 1127 1.29 bouyer return; 1128 1.29 bouyer } 1129 1.29 bouyer 1130 1.29 bouyer /* 1131 1.40 mlelstv * device_reportluns: 1132 1.40 mlelstv * 1133 1.40 mlelstv * Report the known LUNs to which the initiator can send commands 1134 1.40 mlelstv */ 1135 1.40 mlelstv static void 1136 1.40 mlelstv device_reportluns(int argc, char *argv[]) 1137 1.40 mlelstv { 1138 1.40 mlelstv struct scsi_report_luns cmd; 1139 1.40 mlelstv struct { 1140 1.40 mlelstv struct scsi_report_luns_header header; 1141 1.40 mlelstv struct scsi_report_luns_lun desc[1]; 1142 1.40 mlelstv } *data; 1143 1.40 mlelstv u_int32_t dlen, len; 1144 1.40 mlelstv u_int64_t lun; 1145 1.40 mlelstv size_t count, idx; 1146 1.40 mlelstv unsigned long sel; 1147 1.40 mlelstv char *endp; 1148 1.40 mlelstv int i; 1149 1.40 mlelstv 1150 1.40 mlelstv dlen = USHRT_MAX; /* good for > 8000 LUNs */ 1151 1.40 mlelstv data = malloc(dlen); 1152 1.40 mlelstv if (data == NULL) 1153 1.40 mlelstv errx(1, "unable to allocate lun report"); 1154 1.40 mlelstv 1155 1.40 mlelstv memset(&cmd, 0, sizeof(cmd)); 1156 1.40 mlelstv cmd.opcode = SCSI_REPORT_LUNS; 1157 1.40 mlelstv cmd.selectreport = SELECTREPORT_NORMAL; 1158 1.40 mlelstv 1159 1.40 mlelstv /* determine which report to read. */ 1160 1.40 mlelstv for (i = 0; i < argc; i++) { 1161 1.40 mlelstv if (strcmp("normal", argv[i]) == 0) { 1162 1.40 mlelstv cmd.selectreport = SELECTREPORT_NORMAL; 1163 1.40 mlelstv continue; 1164 1.40 mlelstv } 1165 1.40 mlelstv if (strcmp("wellknown", argv[i]) == 0) { 1166 1.40 mlelstv cmd.selectreport = SELECTREPORT_WELLKNOWN; 1167 1.40 mlelstv continue; 1168 1.40 mlelstv } 1169 1.40 mlelstv if (strcmp("all", argv[i]) == 0) { 1170 1.40 mlelstv cmd.selectreport = SELECTREPORT_ALL; 1171 1.40 mlelstv continue; 1172 1.40 mlelstv } 1173 1.40 mlelstv sel = strtoul(argv[i], &endp, 0); 1174 1.40 mlelstv if (*endp != '\0' || sel > 255) 1175 1.40 mlelstv errx(1, "Unknown select report '%s'", argv[i]); 1176 1.40 mlelstv cmd.selectreport = sel; 1177 1.40 mlelstv } 1178 1.40 mlelstv 1179 1.40 mlelstv _lto4b(dlen, &cmd.alloclen[0]); 1180 1.40 mlelstv cmd.control = 0x00; 1181 1.40 mlelstv 1182 1.40 mlelstv scsi_command(fd, &cmd, sizeof(cmd), data, dlen, 30000, SCCMD_READ); 1183 1.40 mlelstv 1184 1.40 mlelstv len = _4btol(data->header.length); 1185 1.40 mlelstv if (len > dlen) { 1186 1.40 mlelstv /* XXX reallocate and retry */ 1187 1.40 mlelstv printf("%s: report truncated %" PRIu32 "to %" PRIu32 "\n", 1188 1.40 mlelstv dvname, len, dlen); 1189 1.40 mlelstv len = dlen; 1190 1.40 mlelstv } 1191 1.40 mlelstv 1192 1.40 mlelstv count = len / sizeof(data->desc[0]); 1193 1.40 mlelstv 1194 1.42 riastrad for (idx = 0; idx < count; idx++) { 1195 1.40 mlelstv lun = _8btol(data->desc[idx].lun); 1196 1.40 mlelstv 1197 1.40 mlelstv /* 1198 1.40 mlelstv * swizzle bits so that LUNs 0..255 are 1199 1.40 mlelstv * mapped to numbers 0..255 1200 1.40 mlelstv */ 1201 1.40 mlelstv lun = (lun & 0xffff000000000000ull) >> 48 1202 1.40 mlelstv | (lun & 0x0000ffff00000000ull) >> 16 1203 1.40 mlelstv | (lun & 0x00000000ffff0000ull) << 16 1204 1.40 mlelstv | (lun & 0x000000000000ffffull) << 48; 1205 1.40 mlelstv 1206 1.40 mlelstv printf("%s: lun %" PRIu64 "\n", dvname, lun); 1207 1.40 mlelstv } 1208 1.40 mlelstv 1209 1.40 mlelstv free(data); 1210 1.40 mlelstv } 1211 1.40 mlelstv 1212 1.40 mlelstv /* 1213 1.39 flxd * device_getrealloc: 1214 1.39 flxd * 1215 1.39 flxd * Get the automatic reallocation parameters for a SCSI disk. 1216 1.39 flxd */ 1217 1.39 flxd static void 1218 1.39 flxd device_getrealloc(int argc, char *argv[]) 1219 1.39 flxd { 1220 1.39 flxd struct { 1221 1.39 flxd struct scsi_mode_parameter_header_6 header; 1222 1.39 flxd struct scsi_general_block_descriptor blk_desc; 1223 1.39 flxd struct page_err_recov err_recov_params; 1224 1.39 flxd } data; 1225 1.39 flxd u_int8_t flags; 1226 1.39 flxd 1227 1.39 flxd /* No arguments. */ 1228 1.39 flxd if (argc != 0) 1229 1.39 flxd usage(); 1230 1.39 flxd 1231 1.39 flxd scsi_mode_sense(fd, 0x01, 0x00, &data, sizeof(data)); 1232 1.39 flxd 1233 1.39 flxd flags = data.err_recov_params.flags; 1234 1.39 flxd if ((flags & (ERR_RECOV_ARRE | ERR_RECOV_AWRE)) == 0) 1235 1.39 flxd printf("%s: no automatic reallocation enabled\n", dvname); 1236 1.39 flxd else { 1237 1.39 flxd printf("%s: automatic read reallocation %senabled\n", dvname, 1238 1.39 flxd (flags & ERR_RECOV_ARRE) ? "" : "not "); 1239 1.39 flxd printf("%s: automatic write reallocation %senabled\n", dvname, 1240 1.39 flxd (flags & ERR_RECOV_AWRE) ? "" : "not "); 1241 1.39 flxd } 1242 1.39 flxd printf("%s: error recovery parameters are %ssavable\n", dvname, 1243 1.39 flxd (data.err_recov_params.pg_code & PGCODE_PS) ? "" : "not "); 1244 1.39 flxd } 1245 1.39 flxd 1246 1.39 flxd /* 1247 1.39 flxd * device_setrealloc: 1248 1.39 flxd * 1249 1.39 flxd * Set the automatic reallocation parameters for a SCSI disk. 1250 1.39 flxd */ 1251 1.39 flxd static void 1252 1.39 flxd device_setrealloc(int argc, char *argv[]) 1253 1.39 flxd { 1254 1.39 flxd struct { 1255 1.39 flxd struct scsi_mode_parameter_header_6 header; 1256 1.39 flxd struct scsi_general_block_descriptor blk_desc; 1257 1.39 flxd struct page_err_recov err_recov_params; 1258 1.39 flxd } data; 1259 1.39 flxd int dlen; 1260 1.39 flxd u_int8_t flags, byte2; 1261 1.39 flxd 1262 1.39 flxd if (argc > 2 || argc == 0) 1263 1.39 flxd usage(); 1264 1.39 flxd 1265 1.39 flxd flags = 0; 1266 1.39 flxd byte2 = 0; 1267 1.39 flxd if (strcmp(argv[0], "none") == 0) 1268 1.39 flxd flags = 0; 1269 1.39 flxd else if (strcmp(argv[0], "r") == 0) 1270 1.39 flxd flags = ERR_RECOV_ARRE; 1271 1.39 flxd else if (strcmp(argv[0], "w") == 0) 1272 1.39 flxd flags = ERR_RECOV_AWRE; 1273 1.39 flxd else if (strcmp(argv[0], "rw") == 0) 1274 1.39 flxd flags = ERR_RECOV_ARRE | ERR_RECOV_AWRE; 1275 1.39 flxd else 1276 1.39 flxd usage(); 1277 1.39 flxd 1278 1.39 flxd if (argc == 2) { 1279 1.39 flxd if (strcmp(argv[1], "save") == 0) 1280 1.39 flxd byte2 = SMS_SP; 1281 1.39 flxd else 1282 1.39 flxd usage(); 1283 1.39 flxd } 1284 1.39 flxd 1285 1.39 flxd scsi_mode_sense(fd, 0x01, 0x00, &data, sizeof(data)); 1286 1.39 flxd 1287 1.39 flxd data.err_recov_params.pg_code &= PGCODE_MASK; 1288 1.39 flxd data.err_recov_params.flags &= ~(ERR_RECOV_ARRE | ERR_RECOV_AWRE); 1289 1.39 flxd data.err_recov_params.flags |= flags; 1290 1.39 flxd 1291 1.39 flxd data.header.data_length = 0; 1292 1.39 flxd 1293 1.39 flxd dlen = sizeof(data.header) + sizeof(data.blk_desc) + 2 + 1294 1.39 flxd data.err_recov_params.pg_length; 1295 1.39 flxd 1296 1.39 flxd scsi_mode_select(fd, byte2, &data, dlen); 1297 1.39 flxd } 1298 1.39 flxd 1299 1.39 flxd /* 1300 1.22 mycroft * device_prevent: 1301 1.22 mycroft * 1302 1.22 mycroft * Issue a prevent to a SCSI device. 1303 1.22 mycroft */ 1304 1.35 jakllsch static void 1305 1.26 xtraeme device_prevent(int argc, char *argv[]) 1306 1.22 mycroft { 1307 1.27 thorpej struct scsi_prevent_allow_medium_removal cmd; 1308 1.22 mycroft 1309 1.22 mycroft /* No arguments. */ 1310 1.22 mycroft if (argc != 0) 1311 1.22 mycroft usage(); 1312 1.22 mycroft 1313 1.22 mycroft memset(&cmd, 0, sizeof(cmd)); 1314 1.22 mycroft 1315 1.27 thorpej cmd.opcode = SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL; 1316 1.27 thorpej cmd.how = SPAMR_PREVENT_DT; /* XXX SMAMR_PREVENT_ALL? */ 1317 1.22 mycroft 1318 1.22 mycroft scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 1319 1.22 mycroft 1320 1.22 mycroft return; 1321 1.22 mycroft } 1322 1.22 mycroft 1323 1.22 mycroft /* 1324 1.22 mycroft * device_allow: 1325 1.22 mycroft * 1326 1.22 mycroft * Issue a stop to a SCSI device. 1327 1.22 mycroft */ 1328 1.35 jakllsch static void 1329 1.26 xtraeme device_allow(int argc, char *argv[]) 1330 1.22 mycroft { 1331 1.27 thorpej struct scsi_prevent_allow_medium_removal cmd; 1332 1.22 mycroft 1333 1.22 mycroft /* No arguments. */ 1334 1.22 mycroft if (argc != 0) 1335 1.22 mycroft usage(); 1336 1.22 mycroft 1337 1.22 mycroft memset(&cmd, 0, sizeof(cmd)); 1338 1.22 mycroft 1339 1.27 thorpej cmd.opcode = SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL; 1340 1.27 thorpej cmd.how = SPAMR_ALLOW; 1341 1.21 mycroft 1342 1.21 mycroft scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 1343 1.21 mycroft 1344 1.21 mycroft return; 1345 1.1 thorpej } 1346 1.16 mjacob 1347 1.16 mjacob /* 1348 1.16 mjacob * device_start: 1349 1.16 mjacob * 1350 1.16 mjacob * Issue a start to a SCSI device. 1351 1.16 mjacob */ 1352 1.35 jakllsch static void 1353 1.26 xtraeme device_start(int argc, char *argv[]) 1354 1.16 mjacob { 1355 1.16 mjacob struct scsipi_start_stop cmd; 1356 1.16 mjacob 1357 1.16 mjacob /* No arguments. */ 1358 1.16 mjacob if (argc != 0) 1359 1.16 mjacob usage(); 1360 1.16 mjacob 1361 1.16 mjacob memset(&cmd, 0, sizeof(cmd)); 1362 1.16 mjacob 1363 1.16 mjacob cmd.opcode = START_STOP; 1364 1.16 mjacob cmd.how = SSS_START; 1365 1.16 mjacob 1366 1.24 fair scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 30000, 0); 1367 1.16 mjacob 1368 1.16 mjacob return; 1369 1.16 mjacob } 1370 1.16 mjacob 1371 1.16 mjacob /* 1372 1.16 mjacob * device_stop: 1373 1.16 mjacob * 1374 1.16 mjacob * Issue a stop to a SCSI device. 1375 1.16 mjacob */ 1376 1.35 jakllsch static void 1377 1.26 xtraeme device_stop(int argc, char *argv[]) 1378 1.16 mjacob { 1379 1.16 mjacob struct scsipi_start_stop cmd; 1380 1.16 mjacob 1381 1.16 mjacob /* No arguments. */ 1382 1.16 mjacob if (argc != 0) 1383 1.16 mjacob usage(); 1384 1.16 mjacob 1385 1.16 mjacob memset(&cmd, 0, sizeof(cmd)); 1386 1.16 mjacob 1387 1.16 mjacob cmd.opcode = START_STOP; 1388 1.16 mjacob cmd.how = SSS_STOP; 1389 1.16 mjacob 1390 1.24 fair scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 30000, 0); 1391 1.16 mjacob 1392 1.16 mjacob return; 1393 1.16 mjacob } 1394 1.16 mjacob 1395 1.16 mjacob /* 1396 1.16 mjacob * device_tur: 1397 1.16 mjacob * 1398 1.29 bouyer * Issue a TEST UNIT READY to a SCSI device. 1399 1.16 mjacob */ 1400 1.35 jakllsch static void 1401 1.26 xtraeme device_tur(int argc, char *argv[]) 1402 1.16 mjacob { 1403 1.27 thorpej struct scsi_test_unit_ready cmd; 1404 1.16 mjacob 1405 1.16 mjacob /* No arguments. */ 1406 1.16 mjacob if (argc != 0) 1407 1.16 mjacob usage(); 1408 1.16 mjacob 1409 1.16 mjacob memset(&cmd, 0, sizeof(cmd)); 1410 1.16 mjacob 1411 1.27 thorpej cmd.opcode = SCSI_TEST_UNIT_READY; 1412 1.16 mjacob 1413 1.16 mjacob scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 1414 1.16 mjacob 1415 1.16 mjacob return; 1416 1.16 mjacob } 1417 1.16 mjacob 1418 1.18 thorpej /* 1419 1.18 thorpej * BUS COMMANDS 1420 1.18 thorpej */ 1421 1.18 thorpej 1422 1.18 thorpej /* 1423 1.18 thorpej * bus_reset: 1424 1.18 thorpej * 1425 1.18 thorpej * Issue a reset to a SCSI bus. 1426 1.18 thorpej */ 1427 1.35 jakllsch static void 1428 1.26 xtraeme bus_reset(int argc, char *argv[]) 1429 1.18 thorpej { 1430 1.18 thorpej 1431 1.18 thorpej /* No arguments. */ 1432 1.18 thorpej if (argc != 0) 1433 1.18 thorpej usage(); 1434 1.16 mjacob 1435 1.18 thorpej if (ioctl(fd, SCBUSIORESET, NULL) != 0) 1436 1.18 thorpej err(1, "SCBUSIORESET"); 1437 1.18 thorpej 1438 1.18 thorpej return; 1439 1.18 thorpej } 1440 1.1 thorpej 1441 1.1 thorpej /* 1442 1.1 thorpej * bus_scan: 1443 1.1 thorpej * 1444 1.1 thorpej * Rescan a SCSI bus for new devices. 1445 1.1 thorpej */ 1446 1.35 jakllsch static void 1447 1.26 xtraeme bus_scan(int argc, char *argv[]) 1448 1.1 thorpej { 1449 1.1 thorpej struct scbusioscan_args args; 1450 1.1 thorpej char *cp; 1451 1.1 thorpej 1452 1.1 thorpej /* Must have two args: target lun */ 1453 1.1 thorpej if (argc != 2) 1454 1.6 hubertf usage(); 1455 1.1 thorpej 1456 1.8 ad if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0) 1457 1.1 thorpej args.sa_target = -1; 1458 1.1 thorpej else { 1459 1.1 thorpej args.sa_target = strtol(argv[0], &cp, 10); 1460 1.1 thorpej if (*cp != '\0' || args.sa_target < 0) 1461 1.12 ad errx(1, "invalid target: %s", argv[0]); 1462 1.1 thorpej } 1463 1.1 thorpej 1464 1.8 ad if (strcmp(argv[1], "any") == 0 || strcmp(argv[1], "all") == 0) 1465 1.1 thorpej args.sa_lun = -1; 1466 1.1 thorpej else { 1467 1.1 thorpej args.sa_lun = strtol(argv[1], &cp, 10); 1468 1.1 thorpej if (*cp != '\0' || args.sa_lun < 0) 1469 1.12 ad errx(1, "invalid lun: %s", argv[1]); 1470 1.1 thorpej } 1471 1.1 thorpej 1472 1.1 thorpej if (ioctl(fd, SCBUSIOSCAN, &args) != 0) 1473 1.1 thorpej err(1, "SCBUSIOSCAN"); 1474 1.14 bouyer 1475 1.14 bouyer return; 1476 1.14 bouyer } 1477 1.14 bouyer 1478 1.14 bouyer /* 1479 1.14 bouyer * bus_detach: 1480 1.14 bouyer * 1481 1.14 bouyer * detach SCSI devices from a bus. 1482 1.14 bouyer */ 1483 1.35 jakllsch static void 1484 1.26 xtraeme bus_detach(int argc, char *argv[]) 1485 1.14 bouyer { 1486 1.14 bouyer struct scbusiodetach_args args; 1487 1.14 bouyer char *cp; 1488 1.14 bouyer 1489 1.14 bouyer /* Must have two args: target lun */ 1490 1.14 bouyer if (argc != 2) 1491 1.14 bouyer usage(); 1492 1.14 bouyer 1493 1.14 bouyer if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0) 1494 1.14 bouyer args.sa_target = -1; 1495 1.14 bouyer else { 1496 1.14 bouyer args.sa_target = strtol(argv[0], &cp, 10); 1497 1.14 bouyer if (*cp != '\0' || args.sa_target < 0) 1498 1.17 grant errx(1, "invalid target: %s", argv[0]); 1499 1.14 bouyer } 1500 1.14 bouyer 1501 1.14 bouyer if (strcmp(argv[1], "any") == 0 || strcmp(argv[1], "all") == 0) 1502 1.14 bouyer args.sa_lun = -1; 1503 1.14 bouyer else { 1504 1.14 bouyer args.sa_lun = strtol(argv[1], &cp, 10); 1505 1.14 bouyer if (*cp != '\0' || args.sa_lun < 0) 1506 1.17 grant errx(1, "invalid lun: %s", argv[1]); 1507 1.14 bouyer } 1508 1.14 bouyer 1509 1.14 bouyer if (ioctl(fd, SCBUSIODETACH, &args) != 0) 1510 1.14 bouyer err(1, "SCBUSIODETACH"); 1511 1.1 thorpej 1512 1.1 thorpej return; 1513 1.1 thorpej } 1514