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