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