Home | History | Annotate | Line # | Download | only in scsictl
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