xref: /netbsd-src/sbin/scsictl/scsictl.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
1 /*	$NetBSD: scsictl.c,v 1.31 2008/04/28 20:23:09 martin Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9  * NASA Ames Research Center.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * scsictl(8) - a program to manipulate SCSI devices and busses.
35  */
36 #include <sys/cdefs.h>
37 
38 #ifndef lint
39 __RCSID("$NetBSD: scsictl.c,v 1.31 2008/04/28 20:23:09 martin Exp $");
40 #endif
41 
42 
43 #include <sys/param.h>
44 #include <sys/ioctl.h>
45 #include <sys/scsiio.h>
46 #include <err.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <limits.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <util.h>
55 
56 #include <dev/scsipi/scsi_spc.h>
57 #include <dev/scsipi/scsipi_all.h>
58 #include <dev/scsipi/scsi_disk.h>
59 #include <dev/scsipi/scsipiconf.h>
60 
61 #include "extern.h"
62 
63 struct command {
64 	const char *cmd_name;
65 	const char *arg_names;
66 	void (*cmd_func)(int, char *[]);
67 };
68 
69 void	usage(void);
70 
71 int	fd;				/* file descriptor for device */
72 const	char *dvname;			/* device name */
73 char	dvname_store[MAXPATHLEN];	/* for opendisk(3) */
74 const	char *cmdname;			/* command user issued */
75 const	char *argnames;			/* helpstring: expected arguments */
76 struct	scsi_addr dvaddr;		/* SCSI device's address */
77 
78 void	device_defects(int, char *[]);
79 void	device_format(int, char *[]);
80 void	device_identify(int, char *[]);
81 void	device_reassign(int, char *[]);
82 void	device_release(int, char *[]);
83 void	device_reserve(int, char *[]);
84 void	device_reset(int, char *[]);
85 void	device_debug(int, char *[]);
86 void	device_prevent(int, char *[]);
87 void	device_allow(int, char *[]);
88 void	device_start(int, char *[]);
89 void	device_stop(int, char *[]);
90 void	device_tur(int, char *[]);
91 void	device_getcache(int, char *[]);
92 void	device_setcache(int, char *[]);
93 void	device_flushcache(int, char *[]);
94 void	device_setspeed(int, char *[]);
95 
96 struct command device_commands[] = {
97 	{ "defects",	"[primary] [grown] [block|byte|physical]",
98 						device_defects },
99 	{ "format",	"[blocksize [immediate]]", 	device_format },
100 	{ "identify",	"",			device_identify },
101 	{ "reassign",	"blkno [blkno [...]]",	device_reassign },
102 	{ "release",	"",			device_release },
103 	{ "reserve",	"",			device_reserve },
104 	{ "reset",	"",			device_reset },
105 	{ "debug",	"level",		device_debug },
106 	{ "prevent",	"",			device_prevent },
107 	{ "allow",	"",			device_allow },
108 	{ "start",	"",			device_start },
109 	{ "stop",	"",			device_stop },
110 	{ "tur",	"",			device_tur },
111 	{ "getcache",	"",			device_getcache },
112 	{ "setcache",	"none|r|w|rw [save]",	device_setcache },
113 	{ "flushcache",	"",			device_flushcache },
114 	{ "setspeed",	"[speed]",		device_setspeed },
115 	{ NULL,		NULL,			NULL },
116 };
117 
118 void	bus_reset(int, char *[]);
119 void	bus_scan(int, char *[]);
120 void	bus_detach(int, char *[]);
121 
122 struct command bus_commands[] = {
123 	{ "reset",	"",			bus_reset },
124 	{ "scan",	"target lun",		bus_scan },
125 	{ "detach",	"target lun",		bus_detach },
126 	{ NULL,		NULL,				NULL },
127 };
128 
129 int
130 main(int argc, char *argv[])
131 {
132 	struct command *commands;
133 	int i;
134 
135 	/* Must have at least: device command */
136 	if (argc < 3)
137 		usage();
138 
139 	/* Skip program name, get and skip device name and command. */
140 	dvname = argv[1];
141 	cmdname = argv[2];
142 	argv += 3;
143 	argc -= 3;
144 
145 	/*
146 	 * Open the device and determine if it's a scsibus or an actual
147 	 * device.  Devices respond to the SCIOCIDENTIFY ioctl.
148 	 */
149 	fd = opendisk(dvname, O_RDWR, dvname_store, sizeof(dvname_store), 0);
150 	if (fd == -1) {
151 		if (errno == ENOENT) {
152 			/*
153 			 * Device doesn't exist.  Probably trying to open
154 			 * a device which doesn't use disk semantics for
155 			 * device name.  Try again, specifying "cooked",
156 			 * which leaves off the "r" in front of the device's
157 			 * name.
158 			 */
159 			fd = opendisk(dvname, O_RDWR, dvname_store,
160 			    sizeof(dvname_store), 1);
161 			if (fd == -1)
162 				err(1, "%s", dvname);
163 		} else
164 			err(1, "%s", dvname);
165 	}
166 
167 	/*
168 	 * Point the dvname at the actual device name that opendisk() opened.
169 	 */
170 	dvname = dvname_store;
171 
172 	if (ioctl(fd, SCIOCIDENTIFY, &dvaddr) < 0)
173 		commands = bus_commands;
174 	else
175 		commands = device_commands;
176 
177 	/* Look up and call the command. */
178 	for (i = 0; commands[i].cmd_name != NULL; i++)
179 		if (strcmp(cmdname, commands[i].cmd_name) == 0)
180 			break;
181 	if (commands[i].cmd_name == NULL)
182 		errx(1, "unknown %s command: %s",
183 		    commands == bus_commands ? "bus" : "device", cmdname);
184 
185 	argnames = commands[i].arg_names;
186 
187 	(*commands[i].cmd_func)(argc, argv);
188 	exit(0);
189 }
190 
191 void
192 usage(void)
193 {
194 	int i;
195 
196 	fprintf(stderr, "usage: %s device command [arg [...]]\n",
197 	    getprogname());
198 
199 	fprintf(stderr, "   Commands pertaining to scsi devices:\n");
200 	for (i=0; device_commands[i].cmd_name != NULL; i++)
201 		fprintf(stderr, "\t%s %s\n", device_commands[i].cmd_name,
202 					    device_commands[i].arg_names);
203 	fprintf(stderr, "   Commands pertaining to scsi busses:\n");
204 	for (i=0; bus_commands[i].cmd_name != NULL; i++)
205 		fprintf(stderr, "\t%s %s\n", bus_commands[i].cmd_name,
206 					    bus_commands[i].arg_names);
207 	fprintf(stderr, "   Use `any' or `all' to wildcard target or lun\n");
208 
209 	exit(1);
210 }
211 
212 /*
213  * DEVICE COMMANDS
214  */
215 
216 /*
217  * device_read_defect:
218  *
219  *	Read primary and/or growth defect list in physical or block
220  *	format from a direct access device.
221  *
222  *	XXX Does not handle very large defect lists. Needs SCSI3 12
223  *	    byte READ DEFECT DATA command.
224  */
225 
226 void	print_bf_dd(union scsi_defect_descriptor *);
227 void	print_bfif_dd(union scsi_defect_descriptor *);
228 void	print_psf_dd(union scsi_defect_descriptor *);
229 
230 void
231 device_defects(int argc, char *argv[])
232 {
233 	struct scsi_read_defect_data cmd;
234 	struct scsi_read_defect_data_data *data;
235 	size_t dlen;
236 	int i, dlfmt = -1;
237 	int defects;
238 	char msg[256];
239 	void (*pfunc)(union scsi_defect_descriptor *);
240 #define RDD_P_G_MASK	0x18
241 #define RDD_DLF_MASK	0x7
242 
243 	dlen = USHRT_MAX; 		/* XXX - this may not be enough room
244 					 * for all of the defects.
245 					 */
246 	data = malloc(dlen);
247 	if (data == NULL)
248 		errx(1, "unable to allocate defect list");
249 	memset(data, 0, dlen);
250 	memset(&cmd, 0, sizeof(cmd));
251 	defects = 0;
252 	pfunc = NULL;
253 
254 	/* determine which defect list(s) to read. */
255 	for (i = 0; i < argc; i++) {
256 		if (strncmp("primary", argv[i], 7) == 0) {
257 			cmd.flags |= RDD_PRIMARY;
258 			continue;
259 		}
260 		if (strncmp("grown", argv[i], 5) == 0) {
261 			cmd.flags |= RDD_GROWN;
262 			continue;
263 		}
264 		break;
265 	}
266 
267 	/* no defect list sepecified, assume both. */
268 	if ((cmd.flags & (RDD_PRIMARY|RDD_GROWN)) == 0)
269 		cmd.flags |= (RDD_PRIMARY|RDD_GROWN);
270 
271 	/* list format option. */
272 	if (i < argc) {
273 		if (strncmp("block", argv[i], 5) == 0) {
274 			cmd.flags |= RDD_BF;
275 			dlfmt = RDD_BF;
276 		}
277 		else if (strncmp("byte", argv[i], 4) == 0) {
278 			cmd.flags |= RDD_BFIF;
279 			dlfmt = RDD_BFIF;
280 		}
281 		else if (strncmp("physical", argv[i], 4) == 0) {
282 			cmd.flags |= RDD_PSF;
283 			dlfmt = RDD_PSF;
284 		}
285 		else {
286 			usage();
287 		}
288 	}
289 
290 	/*
291 	 * no list format specified; since block format not
292 	 * recommended use physical sector format as default.
293 	 */
294 	if (dlfmt < 0) {
295 		cmd.flags |= RDD_PSF;
296 		dlfmt = RDD_PSF;
297 	}
298 
299 	cmd.opcode = SCSI_READ_DEFECT_DATA;
300 	_lto2b(dlen, &cmd.length[0]);
301 
302 	scsi_command(fd, &cmd, sizeof(cmd), data, dlen, 30000, SCCMD_READ);
303 
304 	msg[0] = '\0';
305 
306 	/* is the defect list in the format asked for? */
307 	if ((data->flags & RDD_DLF_MASK) != dlfmt) {
308 		strcpy(msg, "\n\tnotice:"
309 		       "requested defect list format not supported by device\n\n");
310 		dlfmt = (data->flags & RDD_DLF_MASK);
311 	}
312 
313 	if (data->flags & RDD_PRIMARY)
314 		strcat(msg, "primary");
315 
316 	if (data->flags & RDD_GROWN) {
317 		if (data->flags & RDD_PRIMARY)
318 			strcat(msg, " and ");
319 		strcat(msg, "grown");
320 	}
321 
322 	strcat(msg, " defects");
323 
324 	if ((data->flags & RDD_P_G_MASK) == 0)
325 		strcat(msg, ": none reported\n");
326 
327 
328 	printf("%s: scsibus%d target %d lun %d %s",
329 	       dvname, dvaddr.addr.scsi.scbus, dvaddr.addr.scsi.target,
330 	       dvaddr.addr.scsi.lun, msg);
331 
332 	/* device did not return either defect list. */
333 	if ((data->flags & RDD_P_G_MASK) == 0)
334 		return;
335 
336 	switch (dlfmt) {
337 	case RDD_BF:
338 		defects = _2btol(data->length) /
339 				sizeof(struct scsi_defect_descriptor_bf);
340 		pfunc = print_bf_dd;
341 		strcpy(msg, "block address\n"
342 			    "-------------\n");
343 		break;
344 	case RDD_BFIF:
345 		defects = _2btol(data->length) /
346 				sizeof(struct scsi_defect_descriptor_bfif);
347 		pfunc = print_bfif_dd;
348 		strcpy(msg, "              bytes from\n"
349 			    "cylinder head   index\n"
350 			    "-------- ---- ----------\n");
351 		break;
352 	case RDD_PSF:
353 		defects = _2btol(data->length) /
354 				sizeof(struct scsi_defect_descriptor_psf);
355 		pfunc = print_psf_dd;
356 		strcpy(msg, "cylinder head   sector\n"
357 			    "-------- ---- ----------\n");
358 		break;
359 	}
360 
361 	/* device did not return any defects. */
362 	if (defects == 0) {
363 		printf(": none\n");
364 		return;
365 	}
366 
367 	printf(": %d\n", defects);
368 
369 	/* print heading. */
370 	printf("%s", msg);
371 
372 	/* print defect list. */
373 	for (i = 0 ; i < defects; i++) {
374 		pfunc(&data->defect_descriptor[i]);
375 	}
376 
377 	free(data);
378 	return;
379 }
380 
381 /*
382  * print_bf_dd:
383  *
384  *	Print a block format defect descriptor.
385  */
386 void
387 print_bf_dd(union scsi_defect_descriptor *dd)
388 {
389 	u_int32_t block;
390 
391 	block = _4btol(dd->bf.block_address);
392 
393 	printf("%13u\n", block);
394 }
395 
396 #define DEFECTIVE_TRACK	0xffffffff
397 
398 /*
399  * print_bfif_dd:
400  *
401  *	Print a bytes from index format defect descriptor.
402  */
403 void
404 print_bfif_dd(union scsi_defect_descriptor *dd)
405 {
406 	u_int32_t cylinder;
407 	u_int32_t head;
408 	u_int32_t bytes_from_index;
409 
410 	cylinder = _3btol(dd->bfif.cylinder);
411 	head = dd->bfif.head;
412 	bytes_from_index = _4btol(dd->bfif.bytes_from_index);
413 
414 	printf("%8u %4u ", cylinder, head);
415 
416 	if (bytes_from_index == DEFECTIVE_TRACK)
417 		printf("entire track defective\n");
418 	else
419 		printf("%10u\n", bytes_from_index);
420 }
421 
422 /*
423  * print_psf_dd:
424  *
425  *	Print a physical sector format defect descriptor.
426  */
427 void
428 print_psf_dd(union scsi_defect_descriptor *dd)
429 {
430 	u_int32_t cylinder;
431 	u_int32_t head;
432 	u_int32_t sector;
433 
434 	cylinder = _3btol(dd->psf.cylinder);
435 	head = dd->psf.head;
436 	sector = _4btol(dd->psf.sector);
437 
438 	printf("%8u %4u ", cylinder, head);
439 
440 	if (sector == DEFECTIVE_TRACK)
441 		printf("entire track defective\n");
442 	else
443 		printf("%10u\n", sector);
444 }
445 
446 /*
447  * device_format:
448  *
449  *	Format a direct access device.
450  */
451 void
452 device_format(int argc, char *argv[])
453 {
454 	u_int32_t blksize;
455 	int i, j, immediate;
456 #define	PC	(65536/10)
457 	static int complete[] = {
458 	    PC*1, PC*2, PC*3, PC*4, PC*5, PC*6, PC*7, PC*8, PC*9, 65536
459 	};
460 	char *cp, buffer[64];
461 	struct scsi_sense_data sense;
462 	struct scsi_format_unit cmd;
463 	struct {
464 		struct scsi_format_unit_defect_list_header header;
465 		/* optional initialization pattern */
466 		/* optional defect list */
467 	} dfl;
468 	struct {
469 		struct scsi_mode_parameter_header_6 header;
470 		struct scsi_general_block_descriptor blk_desc;
471 		struct page_disk_format format_page;
472 	} mode_page;
473 	struct {
474 		struct scsi_mode_parameter_header_6 header;
475 		struct scsi_general_block_descriptor blk_desc;
476 	} data_select;
477 
478 
479 	/* Blocksize is an optional argument. */
480 	if (argc > 2)
481 		usage();
482 
483 	/*
484 	 * Loop doing Request Sense to clear any pending Unit Attention.
485 	 *
486 	 * Multiple conditions may exist on the drive which are returned
487 	 * in priority order.
488 	 */
489 	for (i = 0; i < 8; i++) {
490 		scsi_request_sense(fd, &sense, sizeof (sense));
491 		if ((j = SSD_SENSE_KEY(sense.flags)) == SKEY_NO_SENSE)
492 			break;
493 	}
494 	/*
495 	 * Make sure we cleared any pending Unit Attention
496 	 */
497 	if (j != SKEY_NO_SENSE) {
498 		cp = scsi_decode_sense((const unsigned char *) &sense, 2,
499 		    buffer, sizeof (buffer));
500 		errx(1, "failed to clean Unit Attention: %s", cp);
501 	}
502 
503 	/*
504 	 * Get the DISK FORMAT mode page.  SCSI-2 recommends specifying the
505 	 * interleave read from this page in the FORMAT UNIT command.
506 	 */
507 	scsi_mode_sense(fd, 0x03, 0x00, &mode_page, sizeof(mode_page));
508 
509 	j = (mode_page.format_page.bytes_s[0] << 8) |
510 	    (mode_page.format_page.bytes_s[1]);
511 
512 	if (j != DEV_BSIZE)
513 		printf("current disk sector size: %hd\n", j);
514 
515 	memset(&cmd, 0, sizeof(cmd));
516 
517 	cmd.opcode = SCSI_FORMAT_UNIT;
518 	memcpy(cmd.interleave, mode_page.format_page.interleave,
519 	    sizeof(cmd.interleave));
520 
521 	/*
522 	 * The blocksize on the device is only changed if the user
523 	 * specified a new blocksize. If not specified the blocksize
524 	 * used for the device will be the Default value in the device.
525 	 * We don't specify the number of blocks since the format
526 	 * command will always reformat the entire drive.  Also by
527 	 * not specifying a block count the drive will reset the
528 	 * block count to the maximum available after the format
529 	 * completes if the blocksize was changed in the format.
530 	 * Finally, the new disk geometry will not but updated on
531 	 * the drive in permanent storage until _AFTER_ the format
532 	 * completes successfully.
533 	 */
534 	if (argc > 0) {
535 		blksize = strtoul(argv[0], &cp, 10);
536 		if (*cp != '\0')
537 			errx(1, "invalid block size: %s", argv[0]);
538 
539 		memset(&data_select, 0, sizeof(data_select));
540 
541 		data_select.header.blk_desc_len =
542 		    sizeof(struct scsi_general_block_descriptor);
543 		/*
544 		 * blklen in desc is 3 bytes with a leading reserved byte
545 		 */
546 		_lto4b(blksize, &data_select.blk_desc.reserved);
547 
548 		/*
549 		 * Issue Mode Select to modify the device blocksize to be
550 		 * used on the Format.  The modified device geometry will
551 		 * be stored as Current and Saved Page 3 parameters when
552 		 * the Format completes.
553 		 */
554 		scsi_mode_select(fd, 0, &data_select, sizeof(data_select));
555 
556 		/*
557 		 * Since user specified a specific block size make sure it
558 		 * gets stored in the device when the format completes.
559 		 *
560 		 * Also scrub the defect list back to the manufacturers
561 		 * original.
562 		 */
563 		cmd.flags = SFU_CMPLST | SFU_FMTDATA;
564 	}
565 
566 	memset(&dfl, 0, sizeof(dfl));
567 
568 	if (argc > 1 && strncmp(argv[1], "imm", 3) == 0) {
569 		/*
570 		 * Signal target for an immediate return from Format.
571 		 *
572 		 * We'll poll for completion status.
573 		 */
574 		dfl.header.flags = DLH_IMMED;
575 		immediate = 1;
576 	} else {
577 		immediate = 0;
578 	}
579 
580 	scsi_command(fd, &cmd, sizeof(cmd), &dfl, sizeof(dfl),
581 	    8 * 60 * 60 * 1000, 0);
582 
583 	/*
584 	 * Poll device for completion of Format
585 	 */
586 	if (immediate) {
587 		i = 0;
588 		printf("formatting.");
589 		fflush(stdout);
590 		do {
591 			scsireq_t req;
592 			struct scsi_test_unit_ready tcmd;
593 
594 			memset(&tcmd, 0, sizeof(cmd));
595 			tcmd.opcode = SCSI_TEST_UNIT_READY;
596 
597 			memset(&req, 0, sizeof(req));
598 			memcpy(req.cmd, &tcmd, 6);
599 			req.cmdlen = 6;
600 			req.timeout = 10000;
601 			req.senselen = SENSEBUFLEN;
602 
603 			if (ioctl(fd, SCIOCCOMMAND, &req) == -1) {
604 				err(1, "SCIOCCOMMAND");
605 			}
606 
607 			if (req.retsts == SCCMD_OK) {
608 				break;
609 			} else if (req.retsts == SCCMD_TIMEOUT) {
610 				fprintf(stderr, "%s: SCSI command timed out",
611 				    dvname);
612 				break;
613 			} else if (req.retsts == SCCMD_BUSY) {
614 				fprintf(stderr, "%s: device is busy",
615 				    dvname);
616 				break;
617 			} else if (req.retsts != SCCMD_SENSE) {
618 				fprintf(stderr,
619 				    "%s: device had unknown status %x", dvname,
620 				    req.retsts);
621 				break;
622 			}
623 			memcpy(&sense, req.sense, sizeof(sense));
624 			if (sense.sks.sks_bytes[0] & SSD_SKSV) {
625 				j = (sense.sks.sks_bytes[1] << 8) |
626 				    (sense.sks.sks_bytes[2]);
627 				if (j >= complete[i]) {
628 					printf(".%d0%%.", ++i);
629 					fflush(stdout);
630 				}
631 			}
632 			sleep(10);
633 		} while (SSD_SENSE_KEY(sense.flags) == SKEY_NOT_READY);
634 		printf(".100%%..done.\n");
635 	}
636 	return;
637 }
638 
639 /*
640  * device_identify:
641  *
642  *	Display the identity of the device, including it's SCSI bus,
643  *	target, lun, and it's vendor/product/revision information.
644  */
645 void
646 device_identify(int argc, char *argv[])
647 {
648 	struct scsipi_inquiry_data inqbuf;
649 	struct scsipi_inquiry cmd;
650 
651 	/* x4 in case every character is escaped, +1 for NUL. */
652 	char vendor[(sizeof(inqbuf.vendor) * 4) + 1],
653 	     product[(sizeof(inqbuf.product) * 4) + 1],
654 	     revision[(sizeof(inqbuf.revision) * 4) + 1];
655 
656 	/* No arguments. */
657 	if (argc != 0)
658 		usage();
659 
660 	memset(&cmd, 0, sizeof(cmd));
661 	memset(&inqbuf, 0, sizeof(inqbuf));
662 
663 	cmd.opcode = INQUIRY;
664 	cmd.length = sizeof(inqbuf);
665 
666 	scsi_command(fd, &cmd, sizeof(cmd), &inqbuf, sizeof(inqbuf),
667 	    10000, SCCMD_READ);
668 
669 	scsi_strvis(vendor, sizeof(vendor), inqbuf.vendor,
670 	    sizeof(inqbuf.vendor));
671 	scsi_strvis(product, sizeof(product), inqbuf.product,
672 	    sizeof(inqbuf.product));
673 	scsi_strvis(revision, sizeof(revision), inqbuf.revision,
674 	    sizeof(inqbuf.revision));
675 
676 	printf("%s: scsibus%d target %d lun %d <%s, %s, %s>\n",
677 	    dvname, dvaddr.addr.scsi.scbus, dvaddr.addr.scsi.target,
678 	    dvaddr.addr.scsi.lun, vendor, product, revision);
679 
680 	return;
681 }
682 
683 /*
684  * device_reassign:
685  *
686  *	Reassign bad blocks on a direct access device.
687  */
688 void
689 device_reassign(int argc, char *argv[])
690 {
691 	struct scsi_reassign_blocks cmd;
692 	struct scsi_reassign_blocks_data *data;
693 	size_t dlen;
694 	u_int32_t blkno;
695 	int i;
696 	char *cp;
697 
698 	/* We get a list of block numbers. */
699 	if (argc < 1)
700 		usage();
701 
702 	/*
703 	 * Allocate the reassign blocks descriptor.  The 4 comes from the
704 	 * size of the block address in the defect descriptor.
705 	 */
706 	dlen = sizeof(struct scsi_reassign_blocks_data) + ((argc - 1) * 4);
707 	data = malloc(dlen);
708 	if (data == NULL)
709 		errx(1, "unable to allocate defect descriptor");
710 	memset(data, 0, dlen);
711 
712 	cmd.opcode = SCSI_REASSIGN_BLOCKS;
713 	cmd.byte2 = 0;
714 	cmd.unused[0] = 0;
715 	cmd.unused[1] = 0;
716 	cmd.unused[2] = 0;
717 	cmd.control = 0;
718 
719 	/* Defect descriptor length. */
720 	_lto2b(argc * 4, data->length);
721 
722 	/* Build the defect descriptor list. */
723 	for (i = 0; i < argc; i++) {
724 		blkno = strtoul(argv[i], &cp, 10);
725 		if (*cp != '\0')
726 			errx(1, "invalid block number: %s", argv[i]);
727 		_lto4b(blkno, data->defect_descriptor[i].dlbaddr);
728 	}
729 
730 	scsi_command(fd, &cmd, sizeof(cmd), data, dlen, 30000, SCCMD_WRITE);
731 
732 	free(data);
733 	return;
734 }
735 
736 /*
737  * device_release:
738  *
739  *	Issue a RELEASE command to a SCSI device.
740  */
741 #ifndef	SCSI_RELEASE
742 #define	SCSI_RELEASE	0x17
743 #endif
744 void
745 device_release(int argc, char *argv[])
746 {
747 	struct scsi_test_unit_ready cmd;	/* close enough */
748 
749 	/* No arguments. */
750 	if (argc != 0)
751 		usage();
752 
753 	memset(&cmd, 0, sizeof(cmd));
754 
755 	cmd.opcode = SCSI_RELEASE;
756 
757 	scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
758 
759 	return;
760 }
761 
762 
763 
764 /*
765  * device_reserve:
766  *
767  *	Issue a RESERVE command to a SCSI device.
768  */
769 #ifndef	SCSI_RESERVE
770 #define	SCSI_RESERVE	0x16
771 #endif
772 void
773 device_reserve(int argc, char *argv[])
774 {
775 	struct scsi_test_unit_ready cmd;	/* close enough */
776 
777 	/* No arguments. */
778 	if (argc != 0)
779 		usage();
780 
781 	memset(&cmd, 0, sizeof(cmd));
782 
783 	cmd.opcode = SCSI_RESERVE;
784 
785 	scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
786 
787 	return;
788 }
789 
790 /*
791  * device_reset:
792  *
793  *	Issue a reset to a SCSI device.
794  */
795 void
796 device_reset(int argc, char *argv[])
797 {
798 
799 	/* No arguments. */
800 	if (argc != 0)
801 		usage();
802 
803 	if (ioctl(fd, SCIOCRESET, NULL) != 0)
804 		err(1, "SCIOCRESET");
805 
806 	return;
807 }
808 
809 /*
810  * device_debug:
811  *
812  *	Set debug level to a SCSI device.
813  *	scsipi will print anything iff SCSIPI_DEBUG set in config.
814  */
815 void
816 device_debug(int argc, char *argv[])
817 {
818 	int lvl;
819 
820 	if (argc < 1)
821 		usage();
822 
823 	lvl = atoi(argv[0]);
824 
825 	if (ioctl(fd, SCIOCDEBUG, &lvl) != 0)
826 		err(1, "SCIOCDEBUG");
827 
828 	return;
829 }
830 
831 /*
832  * device_getcache:
833  *
834  *	Get the caching parameters for a SCSI disk.
835  */
836 void
837 device_getcache(int argc, char *argv[])
838 {
839 	struct {
840 		struct scsi_mode_parameter_header_6 header;
841 		struct scsi_general_block_descriptor blk_desc;
842 		struct page_caching caching_params;
843 	} data;
844 
845 	/* No arguments. */
846 	if (argc != 0)
847 		usage();
848 
849 	scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data));
850 
851 	if ((data.caching_params.flags & (CACHING_RCD|CACHING_WCE)) ==
852 	    CACHING_RCD)
853 		printf("%s: no caches enabled\n", dvname);
854 	else {
855 		printf("%s: read cache %senabled\n", dvname,
856 		    (data.caching_params.flags & CACHING_RCD) ? "not " : "");
857 		printf("%s: write-back cache %senabled\n", dvname,
858 		    (data.caching_params.flags & CACHING_WCE) ? "" : "not ");
859 	}
860 	printf("%s: caching parameters are %ssavable\n", dvname,
861 	    (data.caching_params.pg_code & PGCODE_PS) ? "" : "not ");
862 }
863 
864 /*
865  * device_setcache:
866  *
867  *	Set cache enables for a SCSI disk.
868  */
869 void
870 device_setcache(int argc, char *argv[])
871 {
872 	struct {
873 		struct scsi_mode_parameter_header_6 header;
874 		struct scsi_general_block_descriptor blk_desc;
875 		struct page_caching caching_params;
876 	} data;
877 	int dlen;
878 	u_int8_t flags, byte2;
879 
880 	if (argc > 2 || argc == 0)
881 		usage();
882 
883 	flags = 0;
884 	byte2 = 0;
885 	if (strcmp(argv[0], "none") == 0)
886 		flags = CACHING_RCD;
887 	else if (strcmp(argv[0], "r") == 0)
888 		flags = 0;
889 	else if (strcmp(argv[0], "w") == 0)
890 		flags = CACHING_RCD|CACHING_WCE;
891 	else if (strcmp(argv[0], "rw") == 0)
892 		flags = CACHING_WCE;
893 	else
894 		usage();
895 
896 	if (argc == 2) {
897 		if (strcmp(argv[1], "save") == 0)
898 			byte2 = SMS_SP;
899 		else
900 			usage();
901 	}
902 
903 	scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data));
904 
905 	data.caching_params.pg_code &= PGCODE_MASK;
906 	data.caching_params.flags =
907 	    (data.caching_params.flags & ~(CACHING_RCD|CACHING_WCE)) | flags;
908 
909 	data.caching_params.cache_segment_size[0] = 0;
910 	data.caching_params.cache_segment_size[1] = 0;
911 
912 	data.header.data_length = 0;
913 
914 	dlen = sizeof(data.header) + sizeof(data.blk_desc) + 2 +
915 	    data.caching_params.pg_length;
916 
917 	scsi_mode_select(fd, byte2, &data, dlen);
918 }
919 
920 /*
921  * device_flushcache:
922  *
923  *	Issue a FLUSH CACHE command to a SCSI device.
924  */
925 #ifndef	SCSI_FLUSHCACHE
926 #define	SCSI_FLUSHCACHE	0x35
927 #endif
928 void
929 device_flushcache(int argc, char *argv[])
930 {
931 	struct scsi_test_unit_ready cmd;	/* close enough */
932 
933 	/* No arguments. */
934 	if (argc != 0)
935 		usage();
936 
937 	memset(&cmd, 0, sizeof(cmd));
938 
939 	cmd.opcode = SCSI_FLUSHCACHE;
940 
941 	scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
942 
943 	return;
944 }
945 
946 /*
947  * device_setspeed:
948  *
949  *	Set rotation speed to a CD/DVD drive.
950  */
951 void
952 device_setspeed(int argc, char *argv[])
953 {
954 	u_char cmd[11];
955 	u_char pd[28];
956 	u_int32_t speed;
957 
958 	if (argc != 1)
959 		usage();
960 
961 	speed = atoi(argv[0]) * 177;
962 
963 	memset(&pd, 0, sizeof(pd));
964 	if (speed == 0)
965 		pd[0] = 4; /* restore drive defaults */
966 	pd[8] = 0xff;
967 	pd[9] = 0xff;
968 	pd[10] = 0xff;
969 	pd[11] = 0xff;
970 	pd[12] = pd[20] = (speed >> 24) & 0xff;
971 	pd[13] = pd[21] = (speed >> 16) & 0xff;
972 	pd[14] = pd[22] = (speed >> 8) & 0xff;
973 	pd[15] = pd[23] = speed & 0xff;
974 	pd[18] = pd[26] = 1000 >> 8;
975 	pd[19] = pd[27] = 1000 & 0xff;
976 
977 	memset(&cmd, 0, sizeof(cmd));
978 	cmd[0] = 0xb6;
979 	cmd[10] = sizeof(pd);
980 
981 	scsi_command(fd, &cmd, sizeof(cmd), pd, sizeof(pd), 10000, SCCMD_WRITE);
982 
983 	return;
984 }
985 
986 /*
987  * device_prevent:
988  *
989  *      Issue a prevent to a SCSI device.
990  */
991 void
992 device_prevent(int argc, char *argv[])
993 {
994 	struct scsi_prevent_allow_medium_removal cmd;
995 
996 	/* No arguments. */
997 	if (argc != 0)
998 		usage();
999 
1000 	memset(&cmd, 0, sizeof(cmd));
1001 
1002 	cmd.opcode = SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL;
1003 	cmd.how = SPAMR_PREVENT_DT;	/* XXX SMAMR_PREVENT_ALL? */
1004 
1005 	scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
1006 
1007 	return;
1008 }
1009 
1010 /*
1011  * device_allow:
1012  *
1013  *      Issue a stop to a SCSI device.
1014  */
1015 void
1016 device_allow(int argc, char *argv[])
1017 {
1018 	struct scsi_prevent_allow_medium_removal cmd;
1019 
1020 	/* No arguments. */
1021 	if (argc != 0)
1022 		usage();
1023 
1024 	memset(&cmd, 0, sizeof(cmd));
1025 
1026 	cmd.opcode = SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL;
1027 	cmd.how = SPAMR_ALLOW;
1028 
1029 	scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
1030 
1031 	return;
1032 }
1033 
1034 /*
1035  * device_start:
1036  *
1037  *      Issue a start to a SCSI device.
1038  */
1039 void
1040 device_start(int argc, char *argv[])
1041 {
1042 	struct scsipi_start_stop cmd;
1043 
1044 	/* No arguments. */
1045 	if (argc != 0)
1046 		usage();
1047 
1048 	memset(&cmd, 0, sizeof(cmd));
1049 
1050 	cmd.opcode = START_STOP;
1051 	cmd.how = SSS_START;
1052 
1053 	scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 30000, 0);
1054 
1055 	return;
1056 }
1057 
1058 /*
1059  * device_stop:
1060  *
1061  *      Issue a stop to a SCSI device.
1062  */
1063 void
1064 device_stop(int argc, char *argv[])
1065 {
1066 	struct scsipi_start_stop cmd;
1067 
1068 	/* No arguments. */
1069 	if (argc != 0)
1070 		usage();
1071 
1072 	memset(&cmd, 0, sizeof(cmd));
1073 
1074 	cmd.opcode = START_STOP;
1075 	cmd.how = SSS_STOP;
1076 
1077 	scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 30000, 0);
1078 
1079 	return;
1080 }
1081 
1082 /*
1083  * device_tur:
1084  *
1085  *	Issue a TEST UNIT READY to a SCSI device.
1086  */
1087 void
1088 device_tur(int argc, char *argv[])
1089 {
1090 	struct scsi_test_unit_ready cmd;
1091 
1092 	/* No arguments. */
1093 	if (argc != 0)
1094 		usage();
1095 
1096 	memset(&cmd, 0, sizeof(cmd));
1097 
1098 	cmd.opcode = SCSI_TEST_UNIT_READY;
1099 
1100 	scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
1101 
1102 	return;
1103 }
1104 
1105 /*
1106  * BUS COMMANDS
1107  */
1108 
1109 /*
1110  * bus_reset:
1111  *
1112  *	Issue a reset to a SCSI bus.
1113  */
1114 void
1115 bus_reset(int argc, char *argv[])
1116 {
1117 
1118 	/* No arguments. */
1119 	if (argc != 0)
1120 		usage();
1121 
1122 	if (ioctl(fd, SCBUSIORESET, NULL) != 0)
1123 		err(1, "SCBUSIORESET");
1124 
1125 	return;
1126 }
1127 
1128 /*
1129  * bus_scan:
1130  *
1131  *	Rescan a SCSI bus for new devices.
1132  */
1133 void
1134 bus_scan(int argc, char *argv[])
1135 {
1136 	struct scbusioscan_args args;
1137 	char *cp;
1138 
1139 	/* Must have two args: target lun */
1140 	if (argc != 2)
1141 		usage();
1142 
1143 	if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0)
1144 		args.sa_target = -1;
1145 	else {
1146 		args.sa_target = strtol(argv[0], &cp, 10);
1147 		if (*cp != '\0' || args.sa_target < 0)
1148 			errx(1, "invalid target: %s", argv[0]);
1149 	}
1150 
1151 	if (strcmp(argv[1], "any") == 0 || strcmp(argv[1], "all") == 0)
1152 		args.sa_lun = -1;
1153 	else {
1154 		args.sa_lun = strtol(argv[1], &cp, 10);
1155 		if (*cp != '\0' || args.sa_lun < 0)
1156 			errx(1, "invalid lun: %s", argv[1]);
1157 	}
1158 
1159 	if (ioctl(fd, SCBUSIOSCAN, &args) != 0)
1160 		err(1, "SCBUSIOSCAN");
1161 
1162 	return;
1163 }
1164 
1165 /*
1166  * bus_detach:
1167  *
1168  *	detach SCSI devices from a bus.
1169  */
1170 void
1171 bus_detach(int argc, char *argv[])
1172 {
1173 	struct scbusiodetach_args args;
1174 	char *cp;
1175 
1176 	/* Must have two args: target lun */
1177 	if (argc != 2)
1178 		usage();
1179 
1180 	if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0)
1181 		args.sa_target = -1;
1182 	else {
1183 		args.sa_target = strtol(argv[0], &cp, 10);
1184 		if (*cp != '\0' || args.sa_target < 0)
1185 			errx(1, "invalid target: %s", argv[0]);
1186 	}
1187 
1188 	if (strcmp(argv[1], "any") == 0 || strcmp(argv[1], "all") == 0)
1189 		args.sa_lun = -1;
1190 	else {
1191 		args.sa_lun = strtol(argv[1], &cp, 10);
1192 		if (*cp != '\0' || args.sa_lun < 0)
1193 			errx(1, "invalid lun: %s", argv[1]);
1194 	}
1195 
1196 	if (ioctl(fd, SCBUSIODETACH, &args) != 0)
1197 		err(1, "SCBUSIODETACH");
1198 
1199 	return;
1200 }
1201