scsictl.c revision 1.42 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