1/*	$NetBSD: scsictl.c,v 1.32 2011/05/24 12:04:18 joerg 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.32 2011/05/24 12:04:18 joerg 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
63struct command {
64	const char *cmd_name;
65	const char *arg_names;
66	void (*cmd_func)(int, char *[]);
67};
68
69__dead static void	usage(void);
70
71int	fd;				/* file descriptor for device */
72const	char *dvname;			/* device name */
73char	dvname_store[MAXPATHLEN];	/* for opendisk(3) */
74const	char *cmdname;			/* command user issued */
75const	char *argnames;			/* helpstring: expected arguments */
76struct	scsi_addr dvaddr;		/* SCSI device's address */
77
78void	device_defects(int, char *[]);
79void	device_format(int, char *[]);
80void	device_identify(int, char *[]);
81void	device_reassign(int, char *[]);
82void	device_release(int, char *[]);
83void	device_reserve(int, char *[]);
84void	device_reset(int, char *[]);
85void	device_debug(int, char *[]);
86void	device_prevent(int, char *[]);
87void	device_allow(int, char *[]);
88void	device_start(int, char *[]);
89void	device_stop(int, char *[]);
90void	device_tur(int, char *[]);
91void	device_getcache(int, char *[]);
92void	device_setcache(int, char *[]);
93void	device_flushcache(int, char *[]);
94void	device_setspeed(int, char *[]);
95
96struct 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
118void	bus_reset(int, char *[]);
119void	bus_scan(int, char *[]);
120void	bus_detach(int, char *[]);
121
122struct 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
129int
130main(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
191static void
192usage(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
226void	print_bf_dd(union scsi_defect_descriptor *);
227void	print_bfif_dd(union scsi_defect_descriptor *);
228void	print_psf_dd(union scsi_defect_descriptor *);
229
230void
231device_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 */
386void
387print_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 */
403void
404print_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 */
427void
428print_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 */
451void
452device_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: %d\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 */
645void
646device_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 */
688void
689device_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
744void
745device_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
772void
773device_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 */
795void
796device_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 */
815void
816device_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 */
836void
837device_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 */
869void
870device_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
928void
929device_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 */
951void
952device_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 */
991void
992device_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 */
1015void
1016device_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 */
1039void
1040device_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 */
1063void
1064device_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 */
1087void
1088device_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 */
1114void
1115bus_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 */
1133void
1134bus_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 */
1170void
1171bus_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