150477Speter/*
228415Speter * Copyright (c) 1997-2007 Kenneth D. Merry
328415Speter * All rights reserved.
434768Speter *
528415Speter * Redistribution and use in source and binary forms, with or without
628415Speter * modification, are permitted provided that the following conditions
728415Speter * are met:
828415Speter * 1. Redistributions of source code must retain the above copyright
928415Speter *    notice, this list of conditions and the following disclaimer.
1028415Speter * 2. Redistributions in binary form must reproduce the above copyright
1134768Speter *    notice, this list of conditions and the following disclaimer in the
1228415Speter *    documentation and/or other materials provided with the distribution.
1328415Speter * 3. The name of the author may not be used to endorse or promote products
1428415Speter *    derived from this software without specific prior written permission.
1528415Speter *
1628415Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1734768Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1834768Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19139823Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20139823Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2134768Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2228415Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2334768Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2428415Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2528415Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2628415Speter * SUCH DAMAGE.
2728415Speter */
2828415Speter
2928415Speter#include <sys/cdefs.h>
3028415Speter__FBSDID("$FreeBSD: stable/10/sbin/camcontrol/camcontrol.c 320781 2017-07-07 15:22:29Z asomers $");
3128415Speter
3228415Speter#include <sys/ioctl.h>
3328415Speter#include <sys/stdint.h>
3428415Speter#include <sys/types.h>
3528415Speter#include <sys/stat.h>
3628415Speter#include <sys/endian.h>
3728415Speter#include <sys/sbuf.h>
3828415Speter
3928415Speter#include <stdio.h>
4028415Speter#include <stdlib.h>
4128415Speter#include <string.h>
4228415Speter#include <unistd.h>
43139823Simp#include <inttypes.h>
44139823Simp#include <limits.h>
4534768Speter#include <fcntl.h>
4634768Speter#include <ctype.h>
4734768Speter#include <err.h>
4834768Speter#include <libutil.h>
4934768Speter#ifndef MINIMALISTIC
5028415Speter#include <limits.h>
5128415Speter#include <inttypes.h>
5228415Speter#endif
5334768Speter
5434768Speter#include <cam/cam.h>
5534768Speter#include <cam/cam_debug.h>
5628415Speter#include <cam/cam_ccb.h>
5734768Speter#include <cam/scsi/scsi_all.h>
5834768Speter#include <cam/scsi/scsi_da.h>
5928415Speter#include <cam/scsi/scsi_pass.h>
6034768Speter#include <cam/scsi/scsi_message.h>
6128415Speter#include <cam/scsi/smp_all.h>
6228415Speter#include <cam/ata/ata_all.h>
6328415Speter#include <camlib.h>
6434768Speter#include "camcontrol.h"
6528415Speter
6634768Spetertypedef enum {
6734768Speter	CAM_CMD_NONE		= 0x00000000,
6834768Speter	CAM_CMD_DEVLIST		= 0x00000001,
6928415Speter	CAM_CMD_TUR		= 0x00000002,
7034768Speter	CAM_CMD_INQUIRY		= 0x00000003,
7134768Speter	CAM_CMD_STARTSTOP	= 0x00000004,
7228415Speter	CAM_CMD_RESCAN		= 0x00000005,
7334768Speter	CAM_CMD_READ_DEFECTS	= 0x00000006,
7434768Speter	CAM_CMD_MODE_PAGE	= 0x00000007,
7534768Speter	CAM_CMD_SCSI_CMD	= 0x00000008,
7634768Speter	CAM_CMD_DEVTREE		= 0x00000009,
7734768Speter	CAM_CMD_USAGE		= 0x0000000a,
7834768Speter	CAM_CMD_DEBUG		= 0x0000000b,
7934768Speter	CAM_CMD_RESET		= 0x0000000c,
8034768Speter	CAM_CMD_FORMAT		= 0x0000000d,
8134768Speter	CAM_CMD_TAG		= 0x0000000e,
8234768Speter	CAM_CMD_RATE		= 0x0000000f,
8334768Speter	CAM_CMD_DETACH		= 0x00000010,
8434768Speter	CAM_CMD_REPORTLUNS	= 0x00000011,
8534768Speter	CAM_CMD_READCAP		= 0x00000012,
8634768Speter	CAM_CMD_IDENTIFY	= 0x00000013,
8734768Speter	CAM_CMD_IDLE		= 0x00000014,
8834768Speter	CAM_CMD_STANDBY		= 0x00000015,
8934768Speter	CAM_CMD_SLEEP		= 0x00000016,
9034768Speter	CAM_CMD_SMP_CMD		= 0x00000017,
9134768Speter	CAM_CMD_SMP_RG		= 0x00000018,
9297512Sphk	CAM_CMD_SMP_PC		= 0x00000019,
9334768Speter	CAM_CMD_SMP_PHYLIST	= 0x0000001a,
9434768Speter	CAM_CMD_SMP_MANINFO	= 0x0000001b,
9597512Sphk	CAM_CMD_DOWNLOAD_FW	= 0x0000001c,
9628415Speter	CAM_CMD_SECURITY	= 0x0000001d,
9734768Speter	CAM_CMD_HPA		= 0x0000001e,
9834768Speter	CAM_CMD_SANITIZE	= 0x0000001f,
9934768Speter	CAM_CMD_PERSIST		= 0x00000020,
10034768Speter	CAM_CMD_APM		= 0x00000021,
10134768Speter	CAM_CMD_AAM		= 0x00000022,
10234768Speter	CAM_CMD_ATTRIB		= 0x00000023,
10334768Speter	CAM_CMD_OPCODES		= 0x00000024,
10434768Speter	CAM_CMD_REPROBE		= 0x00000025
10534768Speter} cam_cmdmask;
10634768Speter
10734768Spetertypedef enum {
10834768Speter	CAM_ARG_NONE		= 0x00000000,
10934768Speter	CAM_ARG_VERBOSE		= 0x00000001,
11034768Speter	CAM_ARG_DEVICE		= 0x00000002,
11134768Speter	CAM_ARG_BUS		= 0x00000004,
112231678Stijl	CAM_ARG_TARGET		= 0x00000008,
11334768Speter	CAM_ARG_LUN		= 0x00000010,
11434768Speter	CAM_ARG_EJECT		= 0x00000020,
11534768Speter	CAM_ARG_UNIT		= 0x00000040,
11634768Speter	CAM_ARG_FORMAT_BLOCK	= 0x00000080,
11734768Speter	CAM_ARG_FORMAT_BFI	= 0x00000100,
11834768Speter	CAM_ARG_FORMAT_PHYS	= 0x00000200,
11934768Speter	CAM_ARG_PLIST		= 0x00000400,
12034768Speter	CAM_ARG_GLIST		= 0x00000800,
12128415Speter	CAM_ARG_GET_SERIAL	= 0x00001000,
12228415Speter	CAM_ARG_GET_STDINQ	= 0x00002000,
12328415Speter	CAM_ARG_GET_XFERRATE	= 0x00004000,
12428415Speter	CAM_ARG_INQ_MASK	= 0x00007000,
12534768Speter	CAM_ARG_TIMEOUT		= 0x00020000,
12634768Speter	CAM_ARG_CMD_IN		= 0x00040000,
12734768Speter	CAM_ARG_CMD_OUT		= 0x00080000,
12834768Speter	CAM_ARG_ERR_RECOVER	= 0x00200000,
12934768Speter	CAM_ARG_RETRIES		= 0x00400000,
13034768Speter	CAM_ARG_START_UNIT	= 0x00800000,
13128415Speter	CAM_ARG_DEBUG_INFO	= 0x01000000,
13234768Speter	CAM_ARG_DEBUG_TRACE	= 0x02000000,
13334768Speter	CAM_ARG_DEBUG_SUBTRACE	= 0x04000000,
13434768Speter	CAM_ARG_DEBUG_CDB	= 0x08000000,
13534768Speter	CAM_ARG_DEBUG_XPT	= 0x10000000,
13634768Speter	CAM_ARG_DEBUG_PERIPH	= 0x20000000,
13734768Speter	CAM_ARG_DEBUG_PROBE	= 0x40000000,
13834768Speter} cam_argmask;
13928415Speter
14034768Speterstruct camcontrol_opts {
14134768Speter	const char	*optname;
14228415Speter	uint32_t	cmdnum;
14328415Speter	cam_argmask	argnum;
14428415Speter	const char	*subopt;
14534768Speter};
14634768Speter
14734768Speter#ifndef MINIMALISTIC
14828415Speterstruct ata_res_pass16 {
14928415Speter	u_int16_t reserved[5];
15028415Speter	u_int8_t flags;
15128415Speter	u_int8_t error;
15228415Speter	u_int8_t sector_count_exp;
15328415Speter	u_int8_t sector_count;
15428415Speter	u_int8_t lba_low_exp;
15528415Speter	u_int8_t lba_low;
15628415Speter	u_int8_t lba_mid_exp;
15728415Speter	u_int8_t lba_mid;
15828415Speter	u_int8_t lba_high_exp;
15928415Speter	u_int8_t lba_high;
16028415Speter	u_int8_t device;
16128415Speter	u_int8_t status;
16228415Speter};
16328415Speter
16428415Speterstruct ata_set_max_pwd
16528415Speter{
16628415Speter	u_int16_t reserved1;
16728415Speter	u_int8_t password[32];
16828415Speter	u_int16_t reserved2[239];
16928415Speter};
17028415Speter
17128415Speterstatic struct scsi_nv task_attrs[] = {
17228415Speter	{ "simple", MSG_SIMPLE_Q_TAG },
17328415Speter	{ "head", MSG_HEAD_OF_Q_TAG },
17428415Speter	{ "ordered", MSG_ORDERED_Q_TAG },
17528415Speter	{ "iwr", MSG_IGN_WIDE_RESIDUE },
17628415Speter	{ "aca", MSG_ACA_TASK }
17728415Speter};
17828415Speter
17928415Speterstatic const char scsicmd_opts[] = "a:c:dfi:o:r";
18028415Speterstatic const char readdefect_opts[] = "f:GPqsS:X";
18128415Speterstatic const char negotiate_opts[] = "acD:M:O:qR:T:UW:";
18228415Speterstatic const char smprg_opts[] = "l";
18328415Speterstatic const char smppc_opts[] = "a:A:d:lm:M:o:p:s:S:T:";
18428415Speterstatic const char smpphylist_opts[] = "lq";
18528415Speterstatic char pwd_opt;
18628415Speter#endif
18734768Speter
18834768Speterstatic struct camcontrol_opts option_table[] = {
18934768Speter#ifndef MINIMALISTIC
19034768Speter	{"tur", CAM_CMD_TUR, CAM_ARG_NONE, NULL},
19134768Speter	{"inquiry", CAM_CMD_INQUIRY, CAM_ARG_NONE, "DSR"},
19234768Speter	{"identify", CAM_CMD_IDENTIFY, CAM_ARG_NONE, NULL},
19334768Speter	{"start", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT, NULL},
19434768Speter	{"stop", CAM_CMD_STARTSTOP, CAM_ARG_NONE, NULL},
19534768Speter	{"load", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT | CAM_ARG_EJECT, NULL},
19634768Speter	{"eject", CAM_CMD_STARTSTOP, CAM_ARG_EJECT, NULL},
19734768Speter	{"reportluns", CAM_CMD_REPORTLUNS, CAM_ARG_NONE, "clr:"},
19834768Speter	{"readcapacity", CAM_CMD_READCAP, CAM_ARG_NONE, "bhHNqs"},
19934768Speter	{"reprobe", CAM_CMD_REPROBE, CAM_ARG_NONE, NULL},
20034768Speter#endif /* MINIMALISTIC */
20134768Speter	{"rescan", CAM_CMD_RESCAN, CAM_ARG_NONE, NULL},
20234768Speter	{"reset", CAM_CMD_RESET, CAM_ARG_NONE, NULL},
20334768Speter#ifndef MINIMALISTIC
20434768Speter	{"cmd", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts},
20534768Speter	{"command", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts},
20634768Speter	{"smpcmd", CAM_CMD_SMP_CMD, CAM_ARG_NONE, "r:R:"},
20734768Speter	{"smprg", CAM_CMD_SMP_RG, CAM_ARG_NONE, smprg_opts},
20834768Speter	{"smpreportgeneral", CAM_CMD_SMP_RG, CAM_ARG_NONE, smprg_opts},
20934768Speter	{"smppc", CAM_CMD_SMP_PC, CAM_ARG_NONE, smppc_opts},
21034768Speter	{"smpphycontrol", CAM_CMD_SMP_PC, CAM_ARG_NONE, smppc_opts},
21134768Speter	{"smpplist", CAM_CMD_SMP_PHYLIST, CAM_ARG_NONE, smpphylist_opts},
21228415Speter	{"smpphylist", CAM_CMD_SMP_PHYLIST, CAM_ARG_NONE, smpphylist_opts},
21328415Speter	{"smpmaninfo", CAM_CMD_SMP_MANINFO, CAM_ARG_NONE, "l"},
21428415Speter	{"defects", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts},
21528415Speter	{"defectlist", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts},
21634768Speter#endif /* MINIMALISTIC */
21734768Speter	{"devlist", CAM_CMD_DEVTREE, CAM_ARG_NONE, "-b"},
21834768Speter#ifndef MINIMALISTIC
21934768Speter	{"periphlist", CAM_CMD_DEVLIST, CAM_ARG_NONE, NULL},
22034768Speter	{"modepage", CAM_CMD_MODE_PAGE, CAM_ARG_NONE, "bdelm:P:"},
22134768Speter	{"tags", CAM_CMD_TAG, CAM_ARG_NONE, "N:q"},
22234768Speter	{"negotiate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts},
22334768Speter	{"rate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts},
22434768Speter	{"debug", CAM_CMD_DEBUG, CAM_ARG_NONE, "IPTSXcp"},
22528415Speter	{"format", CAM_CMD_FORMAT, CAM_ARG_NONE, "qrwy"},
22628415Speter	{"sanitize", CAM_CMD_SANITIZE, CAM_ARG_NONE, "a:c:IP:qrUwy"},
22728415Speter	{"idle", CAM_CMD_IDLE, CAM_ARG_NONE, "t:"},
22828415Speter	{"standby", CAM_CMD_STANDBY, CAM_ARG_NONE, "t:"},
22928415Speter	{"sleep", CAM_CMD_SLEEP, CAM_ARG_NONE, ""},
23028415Speter	{"apm", CAM_CMD_APM, CAM_ARG_NONE, "l:"},
23128415Speter	{"aam", CAM_CMD_AAM, CAM_ARG_NONE, "l:"},
23228415Speter	{"fwdownload", CAM_CMD_DOWNLOAD_FW, CAM_ARG_NONE, "f:qsy"},
23328415Speter	{"security", CAM_CMD_SECURITY, CAM_ARG_NONE, "d:e:fh:k:l:qs:T:U:y"},
23428415Speter	{"hpa", CAM_CMD_HPA, CAM_ARG_NONE, "Pflp:qs:U:y"},
23528415Speter	{"persist", CAM_CMD_PERSIST, CAM_ARG_NONE, "ai:I:k:K:o:ps:ST:U"},
23634768Speter	{"attrib", CAM_CMD_ATTRIB, CAM_ARG_NONE, "a:ce:F:p:r:s:T:w:V:"},
23734768Speter	{"opcodes", CAM_CMD_OPCODES, CAM_ARG_NONE, "No:s:T"},
23834768Speter#endif /* MINIMALISTIC */
23934768Speter	{"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
24034768Speter	{"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
24134768Speter	{"-h", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
24234768Speter	{NULL, 0, 0, NULL}
24328415Speter};
24434768Speter
24534768Speterstruct cam_devitem {
24634768Speter	struct device_match_result dev_match;
24734768Speter	int num_periphs;
24834768Speter	struct periph_match_result *periph_matches;
24928415Speter	struct scsi_vpd_device_id *device_id;
25028415Speter	int device_id_len;
25128415Speter	STAILQ_ENTRY(cam_devitem) links;
25228415Speter};
25328415Speter
25428415Speterstruct cam_devlist {
25528415Speter	STAILQ_HEAD(, cam_devitem) dev_queue;
25628415Speter	path_id_t path_id;
25728415Speter};
25828415Speter
25928415Speterstatic cam_cmdmask cmdlist;
26028415Speterstatic cam_argmask arglist;
26128415Speter
26228415Spetercamcontrol_optret getoption(struct camcontrol_opts *table, char *arg,
26328415Speter			    uint32_t *cmdnum, cam_argmask *argnum,
26428415Speter			    const char **subopt);
26528415Speter#ifndef MINIMALISTIC
26634768Speterstatic int getdevlist(struct cam_device *device);
26734768Speter#endif /* MINIMALISTIC */
26834768Speterstatic int getdevtree(int argc, char **argv, char *combinedopt);
26934768Speter#ifndef MINIMALISTIC
27034768Speterstatic int testunitready(struct cam_device *device, int task_attr,
27128415Speter			 int retry_count, int timeout, int quiet);
27228415Speterstatic int scsistart(struct cam_device *device, int startstop, int loadeject,
27328415Speter		     int task_attr, int retry_count, int timeout);
27434768Speterstatic int scsiinquiry(struct cam_device *device, int task_attr,
27528415Speter		       int retry_count, int timeout);
27628415Speterstatic int scsiserial(struct cam_device *device, int task_attr,
27728415Speter		      int retry_count, int timeout);
27828415Speter#endif /* MINIMALISTIC */
27928415Speterstatic int parse_btl(char *tstr, path_id_t *bus, target_id_t *target,
28028415Speter		     lun_id_t *lun, cam_argmask *arglst);
28128415Speterstatic int dorescan_or_reset(int argc, char **argv, int rescan);
28228415Speterstatic int rescan_or_reset_bus(path_id_t bus, int rescan);
28328415Speterstatic int scanlun_or_reset_dev(path_id_t bus, target_id_t target,
28428415Speter    lun_id_t lun, int scan);
28528415Speter#ifndef MINIMALISTIC
28628415Speterstatic int readdefects(struct cam_device *device, int argc, char **argv,
28743305Sdillon		       char *combinedopt, int task_attr, int retry_count,
28828415Speter		       int timeout);
28928415Speterstatic void modepage(struct cam_device *device, int argc, char **argv,
29028415Speter		     char *combinedopt, int task_attr, int retry_count,
29128415Speter		     int timeout);
29234768Speterstatic int scsicmd(struct cam_device *device, int argc, char **argv,
29328415Speter		   char *combinedopt, int task_attr, int retry_count,
29434768Speter		   int timeout);
29534768Speterstatic int smpcmd(struct cam_device *device, int argc, char **argv,
29634768Speter		  char *combinedopt, int retry_count, int timeout);
29728415Speterstatic int smpreportgeneral(struct cam_device *device, int argc, char **argv,
29828415Speter			    char *combinedopt, int retry_count, int timeout);
29934768Speterstatic int smpphycontrol(struct cam_device *device, int argc, char **argv,
30034768Speter			 char *combinedopt, int retry_count, int timeout);
30128415Speterstatic int smpmaninfo(struct cam_device *device, int argc, char **argv,
30228415Speter		      char *combinedopt, int retry_count, int timeout);
30328415Speterstatic int getdevid(struct cam_devitem *item);
30428415Speterstatic int buildbusdevlist(struct cam_devlist *devlist);
30528415Speterstatic void freebusdevlist(struct cam_devlist *devlist);
30628415Speterstatic struct cam_devitem *findsasdevice(struct cam_devlist *devlist,
30728415Speter					 uint64_t sasaddr);
30828415Speterstatic int smpphylist(struct cam_device *device, int argc, char **argv,
30928415Speter		      char *combinedopt, int retry_count, int timeout);
31028415Speterstatic int tagcontrol(struct cam_device *device, int argc, char **argv,
31128415Speter		      char *combinedopt);
31228415Speterstatic void cts_print(struct cam_device *device,
31328415Speter		      struct ccb_trans_settings *cts);
31428415Speterstatic void cpi_print(struct ccb_pathinq *cpi);
31528415Speterstatic int get_cpi(struct cam_device *device, struct ccb_pathinq *cpi);
31628415Speterstatic int get_cgd(struct cam_device *device, struct ccb_getdev *cgd);
31728415Speterstatic int get_print_cts(struct cam_device *device, int user_settings,
31828415Speter			 int quiet, struct ccb_trans_settings *cts);
31928415Speterstatic int ratecontrol(struct cam_device *device, int task_attr,
32028415Speter		       int retry_count, int timeout, int argc, char **argv,
32128415Speter		       char *combinedopt);
32228415Speterstatic int scsiformat(struct cam_device *device, int argc, char **argv,
32328415Speter		      char *combinedopt, int task_attr, int retry_count,
32428415Speter		      int timeout);
32528415Speterstatic int scsisanitize(struct cam_device *device, int argc, char **argv,
32628415Speter			char *combinedopt, int task_attr, int retry_count,
32728415Speter			int timeout);
32828415Speterstatic int scsireportluns(struct cam_device *device, int argc, char **argv,
32928415Speter			  char *combinedopt, int task_attr, int retry_count,
33028415Speter			  int timeout);
33128415Speterstatic int scsireadcapacity(struct cam_device *device, int argc, char **argv,
33228415Speter			    char *combinedopt, int task_attr, int retry_count,
33328415Speter			    int timeout);
33434768Speterstatic int atapm(struct cam_device *device, int argc, char **argv,
33534768Speter		 char *combinedopt, int retry_count, int timeout);
33634768Speterstatic int atasecurity(struct cam_device *device, int retry_count, int timeout,
33734768Speter		       int argc, char **argv, char *combinedopt);
33834768Speterstatic int atahpa(struct cam_device *device, int retry_count, int timeout,
33928415Speter		  int argc, char **argv, char *combinedopt);
34028415Speterstatic int scsiprintoneopcode(struct cam_device *device, int req_opcode,
34128415Speter			      int sa_set, int req_sa, uint8_t *buf,
34234768Speter			      uint32_t valid_len);
34328415Speterstatic int scsiprintopcodes(struct cam_device *device, int td_req, uint8_t *buf,
34428415Speter			    uint32_t valid_len);
34528415Speterstatic int scsiopcodes(struct cam_device *device, int argc, char **argv,
34628415Speter		       char *combinedopt, int task_attr, int retry_count,
34728415Speter		       int timeout, int verbose);
34834768Speterstatic int scsireprobe(struct cam_device *device);
34934768Speter
35034768Speter#endif /* MINIMALISTIC */
35134768Speter#ifndef min
35228415Speter#define min(a,b) (((a)<(b))?(a):(b))
35334768Speter#endif
35428415Speter#ifndef max
35528415Speter#define max(a,b) (((a)>(b))?(a):(b))
35628415Speter#endif
35728415Speter
35828415Spetercamcontrol_optret
35928415Spetergetoption(struct camcontrol_opts *table, char *arg, uint32_t *cmdnum,
36028415Speter	  cam_argmask *argnum, const char **subopt)
36128415Speter{
36234768Speter	struct camcontrol_opts *opts;
36328415Speter	int num_matches = 0;
36428415Speter
36528415Speter	for (opts = table; (opts != NULL) && (opts->optname != NULL);
36628415Speter	     opts++) {
36734768Speter		if (strncmp(opts->optname, arg, strlen(arg)) == 0) {
36828415Speter			*cmdnum = opts->cmdnum;
36934768Speter			*argnum = opts->argnum;
37034768Speter			*subopt = opts->subopt;
37134768Speter			if (++num_matches > 1)
37228415Speter				return(CC_OR_AMBIGUOUS);
37328415Speter		}
37434768Speter	}
37534768Speter
37634768Speter	if (num_matches > 0)
37734768Speter		return(CC_OR_FOUND);
37834768Speter	else
37934768Speter		return(CC_OR_NOT_FOUND);
38034768Speter}
38128415Speter
38228415Speter#ifndef MINIMALISTIC
38334768Speterstatic int
38428415Spetergetdevlist(struct cam_device *device)
38528415Speter{
38634768Speter	union ccb *ccb;
38734768Speter	char status[32];
38828415Speter	int error = 0;
38928415Speter
39028415Speter	ccb = cam_getccb(device);
39128415Speter
39228415Speter	ccb->ccb_h.func_code = XPT_GDEVLIST;
39328415Speter	ccb->ccb_h.flags = CAM_DIR_NONE;
39434768Speter	ccb->ccb_h.retry_count = 1;
39534768Speter	ccb->cgdl.index = 0;
39634768Speter	ccb->cgdl.status = CAM_GDEVLIST_MORE_DEVS;
39734768Speter	while (ccb->cgdl.status == CAM_GDEVLIST_MORE_DEVS) {
39834768Speter		if (cam_send_ccb(device, ccb) < 0) {
39928415Speter			perror("error getting device list");
40028415Speter			cam_freeccb(ccb);
40134768Speter			return(1);
40234768Speter		}
40334768Speter
40428415Speter		status[0] = '\0';
40528415Speter
40628415Speter		switch (ccb->cgdl.status) {
40728415Speter			case CAM_GDEVLIST_MORE_DEVS:
40828415Speter				strcpy(status, "MORE");
40934768Speter				break;
41028415Speter			case CAM_GDEVLIST_LAST_DEVICE:
41128415Speter				strcpy(status, "LAST");
41228415Speter				break;
41328415Speter			case CAM_GDEVLIST_LIST_CHANGED:
41428415Speter				strcpy(status, "CHANGED");
41528415Speter				break;
41628415Speter			case CAM_GDEVLIST_ERROR:
41728415Speter				strcpy(status, "ERROR");
41828415Speter				error = 1;
41928415Speter				break;
42028415Speter		}
42128415Speter
42228415Speter		fprintf(stdout, "%s%d:  generation: %d index: %d status: %s\n",
42328415Speter			ccb->cgdl.periph_name,
42428415Speter			ccb->cgdl.unit_number,
42528415Speter			ccb->cgdl.generation,
42628415Speter			ccb->cgdl.index,
42728415Speter			status);
42828415Speter
42934768Speter		/*
43034768Speter		 * If the list has changed, we need to start over from the
43134768Speter		 * beginning.
43228415Speter		 */
43328415Speter		if (ccb->cgdl.status == CAM_GDEVLIST_LIST_CHANGED)
43428415Speter			ccb->cgdl.index = 0;
43528415Speter	}
43628415Speter
43734768Speter	cam_freeccb(ccb);
43834768Speter
43934768Speter	return(error);
44034768Speter}
44134768Speter#endif /* MINIMALISTIC */
44234768Speter
44328415Speterstatic int
44428415Spetergetdevtree(int argc, char **argv, char *combinedopt)
44528415Speter{
44628415Speter	union ccb ccb;
44728415Speter	int bufsize, fd;
44828415Speter	unsigned int i;
44928415Speter	int need_close = 0;
45028415Speter	int error = 0;
45128415Speter	int skip_device = 0;
45228415Speter	int busonly = 0;
45328415Speter	int c;
45428415Speter
45528415Speter	while ((c = getopt(argc, argv, combinedopt)) != -1) {
45628415Speter		switch(c) {
45728415Speter		case 'b':
45834768Speter			if ((arglist & CAM_ARG_VERBOSE) == 0)
45934768Speter				busonly = 1;
46028415Speter			break;
46128415Speter		default:
46228415Speter			break;
46328415Speter		}
46428415Speter	}
46528415Speter
46628415Speter	if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
46728415Speter		warn("couldn't open %s", XPT_DEVICE);
46828415Speter		return(1);
46928415Speter	}
47028415Speter
47128415Speter	bzero(&ccb, sizeof(union ccb));
47228415Speter
47328415Speter	ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
47428415Speter	ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
47528415Speter	ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
47628415Speter
47728415Speter	ccb.ccb_h.func_code = XPT_DEV_MATCH;
47828415Speter	bufsize = sizeof(struct dev_match_result) * 100;
47928415Speter	ccb.cdm.match_buf_len = bufsize;
48028415Speter	ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
48128415Speter	if (ccb.cdm.matches == NULL) {
48228415Speter		warnx("can't malloc memory for matches");
48328415Speter		close(fd);
48434768Speter		return(1);
48528415Speter	}
48628415Speter	ccb.cdm.num_matches = 0;
48728415Speter
48828415Speter	/*
48928415Speter	 * We fetch all nodes, since we display most of them in the default
49028415Speter	 * case, and all in the verbose case.
49134768Speter	 */
49234768Speter	ccb.cdm.num_patterns = 0;
49334768Speter	ccb.cdm.pattern_buf_len = 0;
49434768Speter
49528415Speter	/*
49628415Speter	 * We do the ioctl multiple times if necessary, in case there are
49728415Speter	 * more than 100 nodes in the EDT.
49828415Speter	 */
49934768Speter	do {
50034768Speter		if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
50128415Speter			warn("error sending CAMIOCOMMAND ioctl");
50234768Speter			error = 1;
50334768Speter			break;
50434768Speter		}
50528415Speter
50628415Speter		if ((ccb.ccb_h.status != CAM_REQ_CMP)
50734768Speter		 || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
50834768Speter		    && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
50934768Speter			warnx("got CAM error %#x, CDM error %d\n",
51034768Speter			      ccb.ccb_h.status, ccb.cdm.status);
51128415Speter			error = 1;
51228415Speter			break;
51355205Speter		}
514245102Speter
51528415Speter		for (i = 0; i < ccb.cdm.num_matches; i++) {
51628415Speter			switch (ccb.cdm.matches[i].type) {
51734768Speter			case DEV_MATCH_BUS: {
51828415Speter				struct bus_match_result *bus_result;
51928415Speter
52028415Speter				/*
52128415Speter				 * Only print the bus information if the
52228415Speter				 * user turns on the verbose flag.
52328415Speter				 */
52428415Speter				if ((busonly == 0) &&
52528415Speter				    (arglist & CAM_ARG_VERBOSE) == 0)
52628415Speter					break;
52734768Speter
52834768Speter				bus_result =
52934768Speter					&ccb.cdm.matches[i].result.bus_result;
53028415Speter
53128415Speter				if (need_close) {
53228415Speter					fprintf(stdout, ")\n");
53328415Speter					need_close = 0;
53428415Speter				}
53528415Speter
53634768Speter				fprintf(stdout, "scbus%d on %s%d bus %d%s\n",
53734768Speter					bus_result->path_id,
53834768Speter					bus_result->dev_name,
53928415Speter					bus_result->unit_number,
54028415Speter					bus_result->bus_id,
54128415Speter					(busonly ? "" : ":"));
54228415Speter				break;
54328415Speter			}
54428415Speter			case DEV_MATCH_DEVICE: {
54528415Speter				struct device_match_result *dev_result;
54628415Speter				char vendor[16], product[48], revision[16];
54728415Speter				char fw[5], tmpstr[256];
54828415Speter
54928415Speter				if (busonly == 1)
55028415Speter					break;
55128415Speter
55228415Speter				dev_result =
55328415Speter				     &ccb.cdm.matches[i].result.device_result;
55428415Speter
55528415Speter				if ((dev_result->flags
55628415Speter				     & DEV_RESULT_UNCONFIGURED)
55728415Speter				 && ((arglist & CAM_ARG_VERBOSE) == 0)) {
55828415Speter					skip_device = 1;
55928415Speter					break;
56028415Speter				} else
56128415Speter					skip_device = 0;
56228415Speter
56334768Speter				if (dev_result->protocol == PROTO_SCSI) {
56434768Speter				    cam_strvis(vendor, dev_result->inq_data.vendor,
56534768Speter					   sizeof(dev_result->inq_data.vendor),
56634768Speter					   sizeof(vendor));
56734768Speter				    cam_strvis(product,
56834768Speter					   dev_result->inq_data.product,
56934768Speter					   sizeof(dev_result->inq_data.product),
57034768Speter					   sizeof(product));
57134768Speter				    cam_strvis(revision,
57234768Speter					   dev_result->inq_data.revision,
57328415Speter					  sizeof(dev_result->inq_data.revision),
57428415Speter					   sizeof(revision));
57534768Speter				    sprintf(tmpstr, "<%s %s %s>", vendor, product,
57628415Speter					revision);
57728415Speter				} else if (dev_result->protocol == PROTO_ATA ||
57828415Speter				    dev_result->protocol == PROTO_SATAPM) {
57928415Speter				    cam_strvis(product,
58028415Speter					   dev_result->ident_data.model,
58128415Speter					   sizeof(dev_result->ident_data.model),
58228415Speter					   sizeof(product));
58328415Speter				    cam_strvis(revision,
58428415Speter					   dev_result->ident_data.revision,
58528415Speter					  sizeof(dev_result->ident_data.revision),
58634768Speter					   sizeof(revision));
58728415Speter				    sprintf(tmpstr, "<%s %s>", product,
58828415Speter					revision);
58928415Speter				} else if (dev_result->protocol == PROTO_SEMB) {
59028415Speter					struct sep_identify_data *sid;
59128415Speter
59228415Speter					sid = (struct sep_identify_data *)
59334768Speter					    &dev_result->ident_data;
59434768Speter					cam_strvis(vendor, sid->vendor_id,
59534768Speter					    sizeof(sid->vendor_id),
59634768Speter					    sizeof(vendor));
59734768Speter					cam_strvis(product, sid->product_id,
59834768Speter					    sizeof(sid->product_id),
59934768Speter					    sizeof(product));
60028415Speter					cam_strvis(revision, sid->product_rev,
60134768Speter					    sizeof(sid->product_rev),
60234768Speter					    sizeof(revision));
60328415Speter					cam_strvis(fw, sid->firmware_rev,
60434768Speter					    sizeof(sid->firmware_rev),
60534768Speter					    sizeof(fw));
60628415Speter					sprintf(tmpstr, "<%s %s %s %s>",
60728415Speter					    vendor, product, revision, fw);
60828415Speter				} else {
60928415Speter				    sprintf(tmpstr, "<>");
61028415Speter				}
61128415Speter				if (need_close) {
61228415Speter					fprintf(stdout, ")\n");
61328415Speter					need_close = 0;
61434768Speter				}
61528415Speter
61628415Speter				fprintf(stdout, "%-33s  at scbus%d "
61728415Speter					"target %d lun %jx (",
61828415Speter					tmpstr,
61928415Speter					dev_result->path_id,
62034768Speter					dev_result->target_id,
62134768Speter					(uintmax_t)dev_result->target_lun);
62234768Speter
62334768Speter				need_close = 1;
62434768Speter
62534768Speter				break;
62634768Speter			}
62734768Speter			case DEV_MATCH_PERIPH: {
62834768Speter				struct periph_match_result *periph_result;
62934768Speter
63028415Speter				periph_result =
63128415Speter				      &ccb.cdm.matches[i].result.periph_result;
63228415Speter
63328415Speter				if (busonly || skip_device != 0)
63428415Speter					break;
63528415Speter
63628415Speter				if (need_close > 1)
63728415Speter					fprintf(stdout, ",");
63828415Speter
63928415Speter				fprintf(stdout, "%s%d",
64028415Speter					periph_result->periph_name,
64128415Speter					periph_result->unit_number);
64228415Speter
64328415Speter				need_close++;
64428415Speter				break;
64528415Speter			}
64628415Speter			default:
64728415Speter				fprintf(stdout, "unknown match type\n");
64834768Speter				break;
64928415Speter			}
65028415Speter		}
65134768Speter
65234768Speter	} while ((ccb.ccb_h.status == CAM_REQ_CMP)
65334768Speter		&& (ccb.cdm.status == CAM_DEV_MATCH_MORE));
65428415Speter
65534768Speter	if (need_close)
65634768Speter		fprintf(stdout, ")\n");
65734768Speter
65834768Speter	close(fd);
65934768Speter
66034768Speter	return(error);
66134768Speter}
66234768Speter
66334768Speter#ifndef MINIMALISTIC
66434768Speterstatic int
66534768Spetertestunitready(struct cam_device *device, int task_attr, int retry_count,
66634768Speter	      int timeout, int quiet)
66734768Speter{
66834768Speter	int error = 0;
66934768Speter	union ccb *ccb;
67034768Speter
67134768Speter	ccb = cam_getccb(device);
67234768Speter
67334768Speter	scsi_test_unit_ready(&ccb->csio,
67434768Speter			     /* retries */ retry_count,
67534768Speter			     /* cbfcnp */ NULL,
67634768Speter			     /* tag_action */ task_attr,
67734768Speter			     /* sense_len */ SSD_FULL_SIZE,
67834768Speter			     /* timeout */ timeout ? timeout : 5000);
67934768Speter
68034768Speter	/* Disable freezing the device queue */
68134768Speter	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
68234768Speter
68328415Speter	if (arglist & CAM_ARG_ERR_RECOVER)
68428415Speter		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
68528415Speter
68628415Speter	if (cam_send_ccb(device, ccb) < 0) {
68728415Speter		if (quiet == 0)
68828415Speter			perror("error sending test unit ready");
68928415Speter
69034768Speter		if (arglist & CAM_ARG_VERBOSE) {
69128415Speter			cam_error_print(device, ccb, CAM_ESF_ALL,
69228415Speter					CAM_EPF_ALL, stderr);
69328415Speter		}
69428415Speter
69528415Speter		cam_freeccb(ccb);
69628415Speter		return(1);
69734768Speter	}
69828415Speter
69928415Speter	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
70028415Speter		if (quiet == 0)
70128415Speter			fprintf(stdout, "Unit is ready\n");
70228415Speter	} else {
70334768Speter		if (quiet == 0)
70428415Speter			fprintf(stdout, "Unit is not ready\n");
70528415Speter		error = 1;
70628415Speter
70728415Speter		if (arglist & CAM_ARG_VERBOSE) {
70828415Speter			cam_error_print(device, ccb, CAM_ESF_ALL,
70928415Speter					CAM_EPF_ALL, stderr);
71028415Speter		}
71128415Speter	}
71228415Speter
71328415Speter	cam_freeccb(ccb);
71434768Speter
71534768Speter	return(error);
71634768Speter}
71734768Speter
71834768Speterstatic int
71934768Speterscsistart(struct cam_device *device, int startstop, int loadeject,
72034768Speter	  int task_attr, int retry_count, int timeout)
72134768Speter{
72234768Speter	union ccb *ccb;
72334768Speter	int error = 0;
72434768Speter
72534768Speter	ccb = cam_getccb(device);
72634768Speter
72734768Speter	/*
72834768Speter	 * If we're stopping, send an ordered tag so the drive in question
72934768Speter	 * will finish any previously queued writes before stopping.  If
73034768Speter	 * the device isn't capable of tagged queueing, or if tagged
73134768Speter	 * queueing is turned off, the tag action is a no-op.  We override
73234768Speter	 * the default simple tag, although this also has the effect of
73334768Speter	 * overriding the user's wishes if he wanted to specify a simple
73434768Speter	 * tag.
73534768Speter	 */
73634768Speter	if ((startstop == 0)
73734768Speter	 && (task_attr == MSG_SIMPLE_Q_TAG))
73834768Speter		task_attr = MSG_ORDERED_Q_TAG;
73928415Speter
74034768Speter	scsi_start_stop(&ccb->csio,
74134768Speter			/* retries */ retry_count,
74234768Speter			/* cbfcnp */ NULL,
74328415Speter			/* tag_action */ task_attr,
74434768Speter			/* start/stop */ startstop,
74534768Speter			/* load_eject */ loadeject,
74628415Speter			/* immediate */ 0,
74728415Speter			/* sense_len */ SSD_FULL_SIZE,
74828415Speter			/* timeout */ timeout ? timeout : 120000);
74928415Speter
75028415Speter	/* Disable freezing the device queue */
75128415Speter	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
75228415Speter
75328415Speter	if (arglist & CAM_ARG_ERR_RECOVER)
75428415Speter		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
75528415Speter
75628415Speter	if (cam_send_ccb(device, ccb) < 0) {
75728415Speter		perror("error sending start unit");
75828415Speter
75928415Speter		if (arglist & CAM_ARG_VERBOSE) {
76028415Speter			cam_error_print(device, ccb, CAM_ESF_ALL,
76128415Speter					CAM_EPF_ALL, stderr);
76228415Speter		}
76328415Speter
76428415Speter		cam_freeccb(ccb);
76528415Speter		return(1);
76628415Speter	}
76728415Speter
76828415Speter	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
76928415Speter		if (startstop) {
77028415Speter			fprintf(stdout, "Unit started successfully");
77128415Speter			if (loadeject)
77228415Speter				fprintf(stdout,", Media loaded\n");
77328415Speter			else
77434768Speter				fprintf(stdout,"\n");
77534768Speter		} else {
77634768Speter			fprintf(stdout, "Unit stopped successfully");
77734768Speter			if (loadeject)
77834768Speter				fprintf(stdout, ", Media ejected\n");
77934768Speter			else
78034768Speter				fprintf(stdout, "\n");
78134768Speter		}
78234768Speter	else {
78334768Speter		error = 1;
78434768Speter		if (startstop)
78534768Speter			fprintf(stdout,
78634768Speter				"Error received from start unit command\n");
78734768Speter		else
78834768Speter			fprintf(stdout,
78934768Speter				"Error received from stop unit command\n");
79034768Speter
79134768Speter		if (arglist & CAM_ARG_VERBOSE) {
79234768Speter			cam_error_print(device, ccb, CAM_ESF_ALL,
79334768Speter					CAM_EPF_ALL, stderr);
79428415Speter		}
79528415Speter	}
79628415Speter
79728415Speter	cam_freeccb(ccb);
79828415Speter
79928415Speter	return(error);
80028415Speter}
80128415Speter
80228415Speterint
80328415Speterscsidoinquiry(struct cam_device *device, int argc, char **argv,
80428415Speter	      char *combinedopt, int task_attr, int retry_count, int timeout)
80528415Speter{
80628415Speter	int c;
80728415Speter	int error = 0;
80834768Speter
80928415Speter	while ((c = getopt(argc, argv, combinedopt)) != -1) {
81028415Speter		switch(c) {
81128415Speter		case 'D':
81228415Speter			arglist |= CAM_ARG_GET_STDINQ;
81328415Speter			break;
81428415Speter		case 'R':
81528415Speter			arglist |= CAM_ARG_GET_XFERRATE;
81628415Speter			break;
81728415Speter		case 'S':
81828415Speter			arglist |= CAM_ARG_GET_SERIAL;
81928415Speter			break;
82028415Speter		default:
82128415Speter			break;
82228415Speter		}
82328415Speter	}
82428415Speter
82528415Speter	/*
82628415Speter	 * If the user didn't specify any inquiry options, he wants all of
82734768Speter	 * them.
82834768Speter	 */
82934768Speter	if ((arglist & CAM_ARG_INQ_MASK) == 0)
83034768Speter		arglist |= CAM_ARG_INQ_MASK;
83134768Speter
83234768Speter	if (arglist & CAM_ARG_GET_STDINQ)
83334768Speter		error = scsiinquiry(device, task_attr, retry_count, timeout);
83434768Speter
83534768Speter	if (error != 0)
83634768Speter		return(error);
83734768Speter
83834768Speter	if (arglist & CAM_ARG_GET_SERIAL)
83934768Speter		scsiserial(device, task_attr, retry_count, timeout);
84034768Speter
84134768Speter	if (arglist & CAM_ARG_GET_XFERRATE)
84234768Speter		error = camxferrate(device);
84334768Speter
84434768Speter	return(error);
84534768Speter}
84634768Speter
84734768Speterstatic int
84834768Speterscsiinquiry(struct cam_device *device, int task_attr, int retry_count,
84934768Speter	    int timeout)
85034768Speter{
85134768Speter	union ccb *ccb;
85234768Speter	struct scsi_inquiry_data *inq_buf;
85334768Speter	int error = 0;
85434768Speter
85534768Speter	ccb = cam_getccb(device);
85634768Speter
85734768Speter	if (ccb == NULL) {
85834768Speter		warnx("couldn't allocate CCB");
85934768Speter		return(1);
86034768Speter	}
86134768Speter
86234768Speter	/* cam_getccb cleans up the header, caller has to zero the payload */
86334768Speter	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
86434768Speter
86534768Speter	inq_buf = (struct scsi_inquiry_data *)malloc(
86634768Speter		sizeof(struct scsi_inquiry_data));
86734768Speter
86834768Speter	if (inq_buf == NULL) {
86934768Speter		cam_freeccb(ccb);
87034768Speter		warnx("can't malloc memory for inquiry\n");
87134768Speter		return(1);
87234768Speter	}
87334768Speter	bzero(inq_buf, sizeof(*inq_buf));
87434768Speter
87534768Speter	/*
87634768Speter	 * Note that although the size of the inquiry buffer is the full
87734768Speter	 * 256 bytes specified in the SCSI spec, we only tell the device
87834768Speter	 * that we have allocated SHORT_INQUIRY_LENGTH bytes.  There are
87934768Speter	 * two reasons for this:
88034768Speter	 *
88134768Speter	 *  - The SCSI spec says that when a length field is only 1 byte,
88234768Speter	 *    a value of 0 will be interpreted as 256.  Therefore
88334768Speter	 *    scsi_inquiry() will convert an inq_len (which is passed in as
88434768Speter	 *    a u_int32_t, but the field in the CDB is only 1 byte) of 256
88534768Speter	 *    to 0.  Evidently, very few devices meet the spec in that
88634768Speter	 *    regard.  Some devices, like many Seagate disks, take the 0 as
88734768Speter	 *    0, and don't return any data.  One Pioneer DVD-R drive
88834768Speter	 *    returns more data than the command asked for.
88934768Speter	 *
89034768Speter	 *    So, since there are numerous devices that just don't work
89134768Speter	 *    right with the full inquiry size, we don't send the full size.
89234768Speter	 *
89334768Speter	 *  - The second reason not to use the full inquiry data length is
89434768Speter	 *    that we don't need it here.  The only reason we issue a
89534768Speter	 *    standard inquiry is to get the vendor name, device name,
89634768Speter	 *    and revision so scsi_print_inquiry() can print them.
89734768Speter	 *
89834768Speter	 * If, at some point in the future, more inquiry data is needed for
89934768Speter	 * some reason, this code should use a procedure similar to the
90034768Speter	 * probe code.  i.e., issue a short inquiry, and determine from
90134768Speter	 * the additional length passed back from the device how much
90234768Speter	 * inquiry data the device supports.  Once the amount the device
90334768Speter	 * supports is determined, issue an inquiry for that amount and no
90434768Speter	 * more.
90534768Speter	 *
90634768Speter	 * KDM, 2/18/2000
90734768Speter	 */
90834768Speter	scsi_inquiry(&ccb->csio,
90934768Speter		     /* retries */ retry_count,
91034768Speter		     /* cbfcnp */ NULL,
91134768Speter		     /* tag_action */ task_attr,
91234768Speter		     /* inq_buf */ (u_int8_t *)inq_buf,
91334768Speter		     /* inq_len */ SHORT_INQUIRY_LENGTH,
91434768Speter		     /* evpd */ 0,
91534768Speter		     /* page_code */ 0,
91634768Speter		     /* sense_len */ SSD_FULL_SIZE,
91734768Speter		     /* timeout */ timeout ? timeout : 5000);
91834768Speter
91934768Speter	/* Disable freezing the device queue */
92034768Speter	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
92134768Speter
92234768Speter	if (arglist & CAM_ARG_ERR_RECOVER)
92334768Speter		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
92434768Speter
92534768Speter	if (cam_send_ccb(device, ccb) < 0) {
92634768Speter		perror("error sending SCSI inquiry");
92734768Speter
92834768Speter		if (arglist & CAM_ARG_VERBOSE) {
92934768Speter			cam_error_print(device, ccb, CAM_ESF_ALL,
93034768Speter					CAM_EPF_ALL, stderr);
93134768Speter		}
93234768Speter
93334768Speter		cam_freeccb(ccb);
93496755Strhodes		return(1);
93534768Speter	}
93634768Speter
93734768Speter	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
93834768Speter		error = 1;
93928415Speter
94028415Speter		if (arglist & CAM_ARG_VERBOSE) {
94128415Speter			cam_error_print(device, ccb, CAM_ESF_ALL,
94234768Speter					CAM_EPF_ALL, stderr);
94334768Speter		}
94428415Speter	}
94528415Speter
94628415Speter	cam_freeccb(ccb);
94734768Speter
94828415Speter	if (error != 0) {
94928415Speter		free(inq_buf);
95028415Speter		return(error);
95128415Speter	}
95228415Speter
95328415Speter	fprintf(stdout, "%s%d: ", device->device_name,
95428415Speter		device->dev_unit_num);
95528415Speter	scsi_print_inquiry(inq_buf);
95628415Speter
95728415Speter	free(inq_buf);
95828415Speter
95928415Speter	return(0);
96028415Speter}
96128415Speter
96228415Speterstatic int
96328415Speterscsiserial(struct cam_device *device, int task_attr, int retry_count,
96497512Sphk	   int timeout)
96534768Speter{
96634768Speter	union ccb *ccb;
96734768Speter	struct scsi_vpd_unit_serial_number *serial_buf;
96834768Speter	char serial_num[SVPD_SERIAL_NUM_SIZE + 1];
96934768Speter	int error = 0;
97034768Speter
97134768Speter	ccb = cam_getccb(device);
97234768Speter
97334768Speter	if (ccb == NULL) {
97434768Speter		warnx("couldn't allocate CCB");
97534768Speter		return(1);
97634768Speter	}
97734768Speter
97834768Speter	/* cam_getccb cleans up the header, caller has to zero the payload */
97934768Speter	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
98097512Sphk
98134768Speter	serial_buf = (struct scsi_vpd_unit_serial_number *)
98234768Speter		malloc(sizeof(*serial_buf));
98334768Speter
98434768Speter	if (serial_buf == NULL) {
98534768Speter		cam_freeccb(ccb);
98634768Speter		warnx("can't malloc memory for serial number");
98734768Speter		return(1);
98834768Speter	}
98934768Speter
99034768Speter	scsi_inquiry(&ccb->csio,
99134768Speter		     /*retries*/ retry_count,
99234768Speter		     /*cbfcnp*/ NULL,
99334768Speter		     /* tag_action */ task_attr,
99434768Speter		     /* inq_buf */ (u_int8_t *)serial_buf,
99534768Speter		     /* inq_len */ sizeof(*serial_buf),
99634768Speter		     /* evpd */ 1,
99734768Speter		     /* page_code */ SVPD_UNIT_SERIAL_NUMBER,
99834768Speter		     /* sense_len */ SSD_FULL_SIZE,
99934768Speter		     /* timeout */ timeout ? timeout : 5000);
100034768Speter
100134768Speter	/* Disable freezing the device queue */
100234768Speter	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
100334768Speter
100434768Speter	if (arglist & CAM_ARG_ERR_RECOVER)
100534768Speter		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
100634768Speter
100734768Speter	if (cam_send_ccb(device, ccb) < 0) {
100828415Speter		warn("error getting serial number");
100928415Speter
101028415Speter		if (arglist & CAM_ARG_VERBOSE) {
101134768Speter			cam_error_print(device, ccb, CAM_ESF_ALL,
101234768Speter					CAM_EPF_ALL, stderr);
1013204552Salfred		}
1014204552Salfred
1015204552Salfred		cam_freeccb(ccb);
1016204552Salfred		free(serial_buf);
1017204552Salfred		return(1);
1018204552Salfred	}
1019204552Salfred
102034768Speter	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
102134768Speter		error = 1;
102234768Speter
102334768Speter		if (arglist & CAM_ARG_VERBOSE) {
102428415Speter			cam_error_print(device, ccb, CAM_ESF_ALL,
102534768Speter					CAM_EPF_ALL, stderr);
1026		}
1027	}
1028
1029	cam_freeccb(ccb);
1030
1031	if (error != 0) {
1032		free(serial_buf);
1033		return(error);
1034	}
1035
1036	bcopy(serial_buf->serial_num, serial_num, serial_buf->length);
1037	serial_num[serial_buf->length] = '\0';
1038
1039	if ((arglist & CAM_ARG_GET_STDINQ)
1040	 || (arglist & CAM_ARG_GET_XFERRATE))
1041		fprintf(stdout, "%s%d: Serial Number ",
1042			device->device_name, device->dev_unit_num);
1043
1044	fprintf(stdout, "%.60s\n", serial_num);
1045
1046	free(serial_buf);
1047
1048	return(0);
1049}
1050
1051int
1052camxferrate(struct cam_device *device)
1053{
1054	struct ccb_pathinq cpi;
1055	u_int32_t freq = 0;
1056	u_int32_t speed = 0;
1057	union ccb *ccb;
1058	u_int mb;
1059	int retval = 0;
1060
1061	if ((retval = get_cpi(device, &cpi)) != 0)
1062		return (1);
1063
1064	ccb = cam_getccb(device);
1065
1066	if (ccb == NULL) {
1067		warnx("couldn't allocate CCB");
1068		return(1);
1069	}
1070
1071	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->cts);
1072
1073	ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1074	ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS;
1075
1076	if (((retval = cam_send_ccb(device, ccb)) < 0)
1077	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
1078		const char error_string[] = "error getting transfer settings";
1079
1080		if (retval < 0)
1081			warn(error_string);
1082		else
1083			warnx(error_string);
1084
1085		if (arglist & CAM_ARG_VERBOSE)
1086			cam_error_print(device, ccb, CAM_ESF_ALL,
1087					CAM_EPF_ALL, stderr);
1088
1089		retval = 1;
1090
1091		goto xferrate_bailout;
1092
1093	}
1094
1095	speed = cpi.base_transfer_speed;
1096	freq = 0;
1097	if (ccb->cts.transport == XPORT_SPI) {
1098		struct ccb_trans_settings_spi *spi =
1099		    &ccb->cts.xport_specific.spi;
1100
1101		if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) {
1102			freq = scsi_calc_syncsrate(spi->sync_period);
1103			speed = freq;
1104		}
1105		if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
1106			speed *= (0x01 << spi->bus_width);
1107		}
1108	} else if (ccb->cts.transport == XPORT_FC) {
1109		struct ccb_trans_settings_fc *fc =
1110		    &ccb->cts.xport_specific.fc;
1111
1112		if (fc->valid & CTS_FC_VALID_SPEED)
1113			speed = fc->bitrate;
1114	} else if (ccb->cts.transport == XPORT_SAS) {
1115		struct ccb_trans_settings_sas *sas =
1116		    &ccb->cts.xport_specific.sas;
1117
1118		if (sas->valid & CTS_SAS_VALID_SPEED)
1119			speed = sas->bitrate;
1120	} else if (ccb->cts.transport == XPORT_ATA) {
1121		struct ccb_trans_settings_pata *pata =
1122		    &ccb->cts.xport_specific.ata;
1123
1124		if (pata->valid & CTS_ATA_VALID_MODE)
1125			speed = ata_mode2speed(pata->mode);
1126	} else if (ccb->cts.transport == XPORT_SATA) {
1127		struct	ccb_trans_settings_sata *sata =
1128		    &ccb->cts.xport_specific.sata;
1129
1130		if (sata->valid & CTS_SATA_VALID_REVISION)
1131			speed = ata_revision2speed(sata->revision);
1132	}
1133
1134	mb = speed / 1000;
1135	if (mb > 0) {
1136		fprintf(stdout, "%s%d: %d.%03dMB/s transfers",
1137			device->device_name, device->dev_unit_num,
1138			mb, speed % 1000);
1139	} else {
1140		fprintf(stdout, "%s%d: %dKB/s transfers",
1141			device->device_name, device->dev_unit_num,
1142			speed);
1143	}
1144
1145	if (ccb->cts.transport == XPORT_SPI) {
1146		struct ccb_trans_settings_spi *spi =
1147		    &ccb->cts.xport_specific.spi;
1148
1149		if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
1150		 && (spi->sync_offset != 0))
1151			fprintf(stdout, " (%d.%03dMHz, offset %d", freq / 1000,
1152				freq % 1000, spi->sync_offset);
1153
1154		if (((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0)
1155		 && (spi->bus_width > 0)) {
1156			if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
1157			 && (spi->sync_offset != 0)) {
1158				fprintf(stdout, ", ");
1159			} else {
1160				fprintf(stdout, " (");
1161			}
1162			fprintf(stdout, "%dbit)", 8 * (0x01 << spi->bus_width));
1163		} else if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
1164		 && (spi->sync_offset != 0)) {
1165			fprintf(stdout, ")");
1166		}
1167	} else if (ccb->cts.transport == XPORT_ATA) {
1168		struct ccb_trans_settings_pata *pata =
1169		    &ccb->cts.xport_specific.ata;
1170
1171		printf(" (");
1172		if (pata->valid & CTS_ATA_VALID_MODE)
1173			printf("%s, ", ata_mode2string(pata->mode));
1174		if ((pata->valid & CTS_ATA_VALID_ATAPI) && pata->atapi != 0)
1175			printf("ATAPI %dbytes, ", pata->atapi);
1176		if (pata->valid & CTS_ATA_VALID_BYTECOUNT)
1177			printf("PIO %dbytes", pata->bytecount);
1178		printf(")");
1179	} else if (ccb->cts.transport == XPORT_SATA) {
1180		struct ccb_trans_settings_sata *sata =
1181		    &ccb->cts.xport_specific.sata;
1182
1183		printf(" (");
1184		if (sata->valid & CTS_SATA_VALID_REVISION)
1185			printf("SATA %d.x, ", sata->revision);
1186		else
1187			printf("SATA, ");
1188		if (sata->valid & CTS_SATA_VALID_MODE)
1189			printf("%s, ", ata_mode2string(sata->mode));
1190		if ((sata->valid & CTS_SATA_VALID_ATAPI) && sata->atapi != 0)
1191			printf("ATAPI %dbytes, ", sata->atapi);
1192		if (sata->valid & CTS_SATA_VALID_BYTECOUNT)
1193			printf("PIO %dbytes", sata->bytecount);
1194		printf(")");
1195	}
1196
1197	if (ccb->cts.protocol == PROTO_SCSI) {
1198		struct ccb_trans_settings_scsi *scsi =
1199		    &ccb->cts.proto_specific.scsi;
1200		if (scsi->valid & CTS_SCSI_VALID_TQ) {
1201			if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) {
1202				fprintf(stdout, ", Command Queueing Enabled");
1203			}
1204		}
1205	}
1206
1207        fprintf(stdout, "\n");
1208
1209xferrate_bailout:
1210
1211	cam_freeccb(ccb);
1212
1213	return(retval);
1214}
1215
1216static void
1217atahpa_print(struct ata_params *parm, u_int64_t hpasize, int header)
1218{
1219	u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
1220				((u_int32_t)parm->lba_size_2 << 16);
1221
1222	u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
1223				((u_int64_t)parm->lba_size48_2 << 16) |
1224				((u_int64_t)parm->lba_size48_3 << 32) |
1225				((u_int64_t)parm->lba_size48_4 << 48);
1226
1227	if (header) {
1228		printf("\nFeature                      "
1229		       "Support  Enabled   Value\n");
1230	}
1231
1232	printf("Host Protected Area (HPA)      ");
1233	if (parm->support.command1 & ATA_SUPPORT_PROTECTED) {
1234		u_int64_t lba = lbasize48 ? lbasize48 : lbasize;
1235		printf("yes      %s     %ju/%ju\n", (hpasize > lba) ? "yes" : "no ",
1236		        lba, hpasize);
1237
1238		printf("HPA - Security                 ");
1239		if (parm->support.command1 & ATA_SUPPORT_MAXSECURITY)
1240			printf("yes\n");
1241		else
1242			printf("no\n");
1243	} else {
1244		printf("no\n");
1245	}
1246}
1247
1248static int
1249atasata(struct ata_params *parm)
1250{
1251
1252
1253	if (parm->satacapabilities != 0xffff &&
1254	    parm->satacapabilities != 0x0000)
1255		return 1;
1256
1257	return 0;
1258}
1259
1260static void
1261atacapprint(struct ata_params *parm)
1262{
1263	u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
1264				((u_int32_t)parm->lba_size_2 << 16);
1265
1266	u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
1267				((u_int64_t)parm->lba_size48_2 << 16) |
1268				((u_int64_t)parm->lba_size48_3 << 32) |
1269				((u_int64_t)parm->lba_size48_4 << 48);
1270
1271	printf("\n");
1272	printf("protocol              ");
1273	printf("ATA/ATAPI-%d", ata_version(parm->version_major));
1274	if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
1275		if (parm->satacapabilities & ATA_SATA_GEN3)
1276			printf(" SATA 3.x\n");
1277		else if (parm->satacapabilities & ATA_SATA_GEN2)
1278			printf(" SATA 2.x\n");
1279		else if (parm->satacapabilities & ATA_SATA_GEN1)
1280			printf(" SATA 1.x\n");
1281		else
1282			printf(" SATA\n");
1283	}
1284	else
1285		printf("\n");
1286	printf("device model          %.40s\n", parm->model);
1287	printf("firmware revision     %.8s\n", parm->revision);
1288	printf("serial number         %.20s\n", parm->serial);
1289	if (parm->enabled.extension & ATA_SUPPORT_64BITWWN) {
1290		printf("WWN                   %04x%04x%04x%04x\n",
1291		    parm->wwn[0], parm->wwn[1], parm->wwn[2], parm->wwn[3]);
1292	}
1293	if (parm->enabled.extension & ATA_SUPPORT_MEDIASN) {
1294		printf("media serial number   %.30s\n",
1295		    parm->media_serial);
1296	}
1297
1298	printf("cylinders             %d\n", parm->cylinders);
1299	printf("heads                 %d\n", parm->heads);
1300	printf("sectors/track         %d\n", parm->sectors);
1301	printf("sector size           logical %u, physical %lu, offset %lu\n",
1302	    ata_logical_sector_size(parm),
1303	    (unsigned long)ata_physical_sector_size(parm),
1304	    (unsigned long)ata_logical_sector_offset(parm));
1305
1306	if (parm->config == ATA_PROTO_CFA ||
1307	    (parm->support.command2 & ATA_SUPPORT_CFA))
1308		printf("CFA supported\n");
1309
1310	printf("LBA%ssupported         ",
1311		parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not ");
1312	if (lbasize)
1313		printf("%d sectors\n", lbasize);
1314	else
1315		printf("\n");
1316
1317	printf("LBA48%ssupported       ",
1318		parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not ");
1319	if (lbasize48)
1320		printf("%ju sectors\n", (uintmax_t)lbasize48);
1321	else
1322		printf("\n");
1323
1324	printf("PIO supported         PIO");
1325	switch (ata_max_pmode(parm)) {
1326	case ATA_PIO4:
1327		printf("4");
1328		break;
1329	case ATA_PIO3:
1330		printf("3");
1331		break;
1332	case ATA_PIO2:
1333		printf("2");
1334		break;
1335	case ATA_PIO1:
1336		printf("1");
1337		break;
1338	default:
1339		printf("0");
1340	}
1341	if ((parm->capabilities1 & ATA_SUPPORT_IORDY) == 0)
1342		printf(" w/o IORDY");
1343	printf("\n");
1344
1345	printf("DMA%ssupported         ",
1346		parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not ");
1347	if (parm->capabilities1 & ATA_SUPPORT_DMA) {
1348		if (parm->mwdmamodes & 0xff) {
1349			printf("WDMA");
1350			if (parm->mwdmamodes & 0x04)
1351				printf("2");
1352			else if (parm->mwdmamodes & 0x02)
1353				printf("1");
1354			else if (parm->mwdmamodes & 0x01)
1355				printf("0");
1356			printf(" ");
1357		}
1358		if ((parm->atavalid & ATA_FLAG_88) &&
1359		    (parm->udmamodes & 0xff)) {
1360			printf("UDMA");
1361			if (parm->udmamodes & 0x40)
1362				printf("6");
1363			else if (parm->udmamodes & 0x20)
1364				printf("5");
1365			else if (parm->udmamodes & 0x10)
1366				printf("4");
1367			else if (parm->udmamodes & 0x08)
1368				printf("3");
1369			else if (parm->udmamodes & 0x04)
1370				printf("2");
1371			else if (parm->udmamodes & 0x02)
1372				printf("1");
1373			else if (parm->udmamodes & 0x01)
1374				printf("0");
1375			printf(" ");
1376		}
1377	}
1378	printf("\n");
1379
1380	if (parm->media_rotation_rate == 1) {
1381		printf("media RPM             non-rotating\n");
1382	} else if (parm->media_rotation_rate >= 0x0401 &&
1383	    parm->media_rotation_rate <= 0xFFFE) {
1384		printf("media RPM             %d\n",
1385			parm->media_rotation_rate);
1386	}
1387
1388	printf("\nFeature                      "
1389		"Support  Enabled   Value           Vendor\n");
1390	printf("read ahead                     %s	%s\n",
1391		parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no",
1392		parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no");
1393	printf("write cache                    %s	%s\n",
1394		parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no",
1395		parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no");
1396	printf("flush cache                    %s	%s\n",
1397		parm->support.command2 & ATA_SUPPORT_FLUSHCACHE ? "yes" : "no",
1398		parm->enabled.command2 & ATA_SUPPORT_FLUSHCACHE ? "yes" : "no");
1399	printf("overlap                        %s\n",
1400		parm->capabilities1 & ATA_SUPPORT_OVERLAP ? "yes" : "no");
1401	printf("Tagged Command Queuing (TCQ)   %s	%s",
1402		parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
1403		parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no");
1404		if (parm->support.command2 & ATA_SUPPORT_QUEUED) {
1405			printf("	%d tags\n",
1406			    ATA_QUEUE_LEN(parm->queue) + 1);
1407		} else
1408			printf("\n");
1409	printf("Native Command Queuing (NCQ)   ");
1410	if (parm->satacapabilities != 0xffff &&
1411	    (parm->satacapabilities & ATA_SUPPORT_NCQ)) {
1412		printf("yes		%d tags\n",
1413		    ATA_QUEUE_LEN(parm->queue) + 1);
1414	} else
1415		printf("no\n");
1416
1417	printf("NCQ Queue Management           %s\n", atasata(parm) &&
1418		parm->satacapabilities2 & ATA_SUPPORT_NCQ_QMANAGEMENT ?
1419		"yes" : "no");
1420	printf("NCQ Streaming                  %s\n", atasata(parm) &&
1421		parm->satacapabilities2 & ATA_SUPPORT_NCQ_STREAM ?
1422		"yes" : "no");
1423	printf("Receive & Send FPDMA Queued    %s\n", atasata(parm) &&
1424		parm->satacapabilities2 & ATA_SUPPORT_RCVSND_FPDMA_QUEUED ?
1425		"yes" : "no");
1426
1427	printf("SMART                          %s	%s\n",
1428		parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no",
1429		parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no");
1430	printf("microcode download             %s	%s\n",
1431		parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no",
1432		parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no");
1433	printf("security                       %s	%s\n",
1434		parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no",
1435		parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no");
1436	printf("power management               %s	%s\n",
1437		parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no",
1438		parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no");
1439	printf("advanced power management      %s	%s",
1440		parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no",
1441		parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no");
1442		if (parm->support.command2 & ATA_SUPPORT_APM) {
1443			printf("	%d/0x%02X\n",
1444			    parm->apm_value & 0xff, parm->apm_value & 0xff);
1445		} else
1446			printf("\n");
1447	printf("automatic acoustic management  %s	%s",
1448		parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
1449		parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no");
1450		if (parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC) {
1451			printf("	%d/0x%02X	%d/0x%02X\n",
1452			    ATA_ACOUSTIC_CURRENT(parm->acoustic),
1453			    ATA_ACOUSTIC_CURRENT(parm->acoustic),
1454			    ATA_ACOUSTIC_VENDOR(parm->acoustic),
1455			    ATA_ACOUSTIC_VENDOR(parm->acoustic));
1456		} else
1457			printf("\n");
1458	printf("media status notification      %s	%s\n",
1459		parm->support.command2 & ATA_SUPPORT_NOTIFY ? "yes" : "no",
1460		parm->enabled.command2 & ATA_SUPPORT_NOTIFY ? "yes" : "no");
1461	printf("power-up in Standby            %s	%s\n",
1462		parm->support.command2 & ATA_SUPPORT_STANDBY ? "yes" : "no",
1463		parm->enabled.command2 & ATA_SUPPORT_STANDBY ? "yes" : "no");
1464	printf("write-read-verify              %s	%s",
1465		parm->support2 & ATA_SUPPORT_WRITEREADVERIFY ? "yes" : "no",
1466		parm->enabled2 & ATA_SUPPORT_WRITEREADVERIFY ? "yes" : "no");
1467		if (parm->support2 & ATA_SUPPORT_WRITEREADVERIFY) {
1468			printf("	%d/0x%x\n",
1469			    parm->wrv_mode, parm->wrv_mode);
1470		} else
1471			printf("\n");
1472	printf("unload                         %s	%s\n",
1473		parm->support.extension & ATA_SUPPORT_UNLOAD ? "yes" : "no",
1474		parm->enabled.extension & ATA_SUPPORT_UNLOAD ? "yes" : "no");
1475	printf("general purpose logging        %s	%s\n",
1476		parm->support.extension & ATA_SUPPORT_GENLOG ? "yes" : "no",
1477		parm->enabled.extension & ATA_SUPPORT_GENLOG ? "yes" : "no");
1478	printf("free-fall                      %s	%s\n",
1479		parm->support2 & ATA_SUPPORT_FREEFALL ? "yes" : "no",
1480		parm->enabled2 & ATA_SUPPORT_FREEFALL ? "yes" : "no");
1481	printf("Data Set Management (DSM/TRIM) ");
1482	if (parm->support_dsm & ATA_SUPPORT_DSM_TRIM) {
1483		printf("yes\n");
1484		printf("DSM - max 512byte blocks       ");
1485		if (parm->max_dsm_blocks == 0x00)
1486			printf("yes              not specified\n");
1487		else
1488			printf("yes              %d\n",
1489				parm->max_dsm_blocks);
1490
1491		printf("DSM - deterministic read       ");
1492		if (parm->support3 & ATA_SUPPORT_DRAT) {
1493			if (parm->support3 & ATA_SUPPORT_RZAT)
1494				printf("yes              zeroed\n");
1495			else
1496				printf("yes              any value\n");
1497		} else {
1498			printf("no\n");
1499		}
1500	} else {
1501		printf("no\n");
1502	}
1503}
1504
1505static int
1506scsi_cam_pass_16_send(struct cam_device *device, union ccb *ccb, int quiet)
1507{
1508	struct ata_pass_16 *ata_pass_16;
1509	struct ata_cmd ata_cmd;
1510
1511	ata_pass_16 = (struct ata_pass_16 *)ccb->csio.cdb_io.cdb_bytes;
1512	ata_cmd.command = ata_pass_16->command;
1513	ata_cmd.control = ata_pass_16->control;
1514	ata_cmd.features = ata_pass_16->features;
1515
1516	if (arglist & CAM_ARG_VERBOSE) {
1517		warnx("sending ATA %s via pass_16 with timeout of %u msecs",
1518		      ata_op_string(&ata_cmd),
1519		      ccb->csio.ccb_h.timeout);
1520	}
1521
1522	/* Disable freezing the device queue */
1523	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
1524
1525	if (arglist & CAM_ARG_ERR_RECOVER)
1526		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
1527
1528	if (cam_send_ccb(device, ccb) < 0) {
1529		if (quiet != 1 || arglist & CAM_ARG_VERBOSE) {
1530			warn("error sending ATA %s via pass_16",
1531			     ata_op_string(&ata_cmd));
1532		}
1533
1534		if (arglist & CAM_ARG_VERBOSE) {
1535			cam_error_print(device, ccb, CAM_ESF_ALL,
1536					CAM_EPF_ALL, stderr);
1537		}
1538
1539		return (1);
1540	}
1541
1542	if (!(ata_pass_16->flags & AP_FLAG_CHK_COND) &&
1543	    (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1544		if (quiet != 1 || arglist & CAM_ARG_VERBOSE) {
1545			warnx("ATA %s via pass_16 failed",
1546			      ata_op_string(&ata_cmd));
1547		}
1548		if (arglist & CAM_ARG_VERBOSE) {
1549			cam_error_print(device, ccb, CAM_ESF_ALL,
1550					CAM_EPF_ALL, stderr);
1551		}
1552
1553		return (1);
1554	}
1555
1556	return (0);
1557}
1558
1559
1560static int
1561ata_cam_send(struct cam_device *device, union ccb *ccb, int quiet)
1562{
1563	if (arglist & CAM_ARG_VERBOSE) {
1564		warnx("sending ATA %s with timeout of %u msecs",
1565		      ata_op_string(&(ccb->ataio.cmd)),
1566		      ccb->ataio.ccb_h.timeout);
1567	}
1568
1569	/* Disable freezing the device queue */
1570	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
1571
1572	if (arglist & CAM_ARG_ERR_RECOVER)
1573		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
1574
1575	if (cam_send_ccb(device, ccb) < 0) {
1576		if (quiet != 1 || arglist & CAM_ARG_VERBOSE) {
1577			warn("error sending ATA %s",
1578			     ata_op_string(&(ccb->ataio.cmd)));
1579		}
1580
1581		if (arglist & CAM_ARG_VERBOSE) {
1582			cam_error_print(device, ccb, CAM_ESF_ALL,
1583					CAM_EPF_ALL, stderr);
1584		}
1585
1586		return (1);
1587	}
1588
1589	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1590		if (quiet != 1 || arglist & CAM_ARG_VERBOSE) {
1591			warnx("ATA %s failed: %d",
1592			      ata_op_string(&(ccb->ataio.cmd)), quiet);
1593		}
1594
1595		if (arglist & CAM_ARG_VERBOSE) {
1596			cam_error_print(device, ccb, CAM_ESF_ALL,
1597					CAM_EPF_ALL, stderr);
1598		}
1599
1600		return (1);
1601	}
1602
1603	return (0);
1604}
1605
1606static int
1607ata_do_pass_16(struct cam_device *device, union ccb *ccb, int retries,
1608	       u_int32_t flags, u_int8_t protocol, u_int8_t ata_flags,
1609	       u_int8_t tag_action, u_int8_t command, u_int8_t features,
1610	       u_int64_t lba, u_int8_t sector_count, u_int8_t *data_ptr,
1611	       u_int16_t dxfer_len, int timeout, int quiet)
1612{
1613	if (data_ptr != NULL) {
1614		ata_flags |= AP_FLAG_BYT_BLOK_BYTES |
1615			    AP_FLAG_TLEN_SECT_CNT;
1616		if (flags & CAM_DIR_OUT)
1617			ata_flags |= AP_FLAG_TDIR_TO_DEV;
1618		else
1619			ata_flags |= AP_FLAG_TDIR_FROM_DEV;
1620	} else {
1621		ata_flags |= AP_FLAG_TLEN_NO_DATA;
1622	}
1623
1624	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
1625
1626	scsi_ata_pass_16(&ccb->csio,
1627			 retries,
1628			 NULL,
1629			 flags,
1630			 tag_action,
1631			 protocol,
1632			 ata_flags,
1633			 features,
1634			 sector_count,
1635			 lba,
1636			 command,
1637			 /*control*/0,
1638			 data_ptr,
1639			 dxfer_len,
1640			 /*sense_len*/SSD_FULL_SIZE,
1641			 timeout);
1642
1643	return scsi_cam_pass_16_send(device, ccb, quiet);
1644}
1645
1646static int
1647ata_try_pass_16(struct cam_device *device)
1648{
1649	struct ccb_pathinq cpi;
1650
1651	if (get_cpi(device, &cpi) != 0) {
1652		warnx("couldn't get CPI");
1653		return (-1);
1654	}
1655
1656	if (cpi.protocol == PROTO_SCSI) {
1657		/* possibly compatible with pass_16 */
1658		return (1);
1659	}
1660
1661	/* likely not compatible with pass_16 */
1662	return (0);
1663}
1664
1665static int
1666ata_do_28bit_cmd(struct cam_device *device, union ccb *ccb, int retries,
1667		 u_int32_t flags, u_int8_t protocol, u_int8_t tag_action,
1668		 u_int8_t command, u_int8_t features, u_int32_t lba,
1669		 u_int8_t sector_count, u_int8_t *data_ptr, u_int16_t dxfer_len,
1670		 int timeout, int quiet)
1671{
1672
1673
1674	switch (ata_try_pass_16(device)) {
1675	case -1:
1676		return (1);
1677	case 1:
1678		/* Try using SCSI Passthrough */
1679		return ata_do_pass_16(device, ccb, retries, flags, protocol,
1680				      0, tag_action, command, features, lba,
1681				      sector_count, data_ptr, dxfer_len,
1682				      timeout, quiet);
1683	}
1684
1685	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->ataio);
1686	cam_fill_ataio(&ccb->ataio,
1687		       retries,
1688		       NULL,
1689		       flags,
1690		       tag_action,
1691		       data_ptr,
1692		       dxfer_len,
1693		       timeout);
1694
1695	ata_28bit_cmd(&ccb->ataio, command, features, lba, sector_count);
1696	return ata_cam_send(device, ccb, quiet);
1697}
1698
1699static int
1700ata_do_cmd(struct cam_device *device, union ccb *ccb, int retries,
1701	   u_int32_t flags, u_int8_t protocol, u_int8_t ata_flags,
1702	   u_int8_t tag_action, u_int8_t command, u_int8_t features,
1703	   u_int64_t lba, u_int8_t sector_count, u_int8_t *data_ptr,
1704	   u_int16_t dxfer_len, int timeout, int force48bit)
1705{
1706	int retval;
1707
1708	retval = ata_try_pass_16(device);
1709	if (retval == -1)
1710		return (1);
1711
1712	if (retval == 1) {
1713		int error;
1714
1715		/* Try using SCSI Passthrough */
1716		error = ata_do_pass_16(device, ccb, retries, flags, protocol,
1717				      ata_flags, tag_action, command, features,
1718				      lba, sector_count, data_ptr, dxfer_len,
1719				      timeout, 0);
1720
1721		if (ata_flags & AP_FLAG_CHK_COND) {
1722			/* Decode ata_res from sense data */
1723			struct ata_res_pass16 *res_pass16;
1724			struct ata_res *res;
1725			u_int i;
1726			u_int16_t *ptr;
1727
1728			/* sense_data is 4 byte aligned */
1729			ptr = (uint16_t*)(uintptr_t)&ccb->csio.sense_data;
1730			for (i = 0; i < sizeof(*res_pass16) / 2; i++)
1731				ptr[i] = le16toh(ptr[i]);
1732
1733			/* sense_data is 4 byte aligned */
1734			res_pass16 = (struct ata_res_pass16 *)(uintptr_t)
1735			    &ccb->csio.sense_data;
1736			res = &ccb->ataio.res;
1737			res->flags = res_pass16->flags;
1738			res->status = res_pass16->status;
1739			res->error = res_pass16->error;
1740			res->lba_low = res_pass16->lba_low;
1741			res->lba_mid = res_pass16->lba_mid;
1742			res->lba_high = res_pass16->lba_high;
1743			res->device = res_pass16->device;
1744			res->lba_low_exp = res_pass16->lba_low_exp;
1745			res->lba_mid_exp = res_pass16->lba_mid_exp;
1746			res->lba_high_exp = res_pass16->lba_high_exp;
1747			res->sector_count = res_pass16->sector_count;
1748			res->sector_count_exp = res_pass16->sector_count_exp;
1749		}
1750
1751		return (error);
1752	}
1753
1754	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->ataio);
1755	cam_fill_ataio(&ccb->ataio,
1756		       retries,
1757		       NULL,
1758		       flags,
1759		       tag_action,
1760		       data_ptr,
1761		       dxfer_len,
1762		       timeout);
1763
1764	if (force48bit || lba > ATA_MAX_28BIT_LBA)
1765		ata_48bit_cmd(&ccb->ataio, command, features, lba, sector_count);
1766	else
1767		ata_28bit_cmd(&ccb->ataio, command, features, lba, sector_count);
1768
1769	if (ata_flags & AP_FLAG_CHK_COND)
1770		ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT;
1771
1772	return ata_cam_send(device, ccb, 0);
1773}
1774
1775static void
1776dump_data(uint16_t *ptr, uint32_t len)
1777{
1778	u_int i;
1779
1780	for (i = 0; i < len / 2; i++) {
1781		if ((i % 8) == 0)
1782			printf(" %3d: ", i);
1783		printf("%04hx ", ptr[i]);
1784		if ((i % 8) == 7)
1785			printf("\n");
1786	}
1787	if ((i % 8) != 7)
1788		printf("\n");
1789}
1790
1791static int
1792atahpa_proc_resp(struct cam_device *device, union ccb *ccb,
1793		 int is48bit, u_int64_t *hpasize)
1794{
1795	struct ata_res *res;
1796
1797	res = &ccb->ataio.res;
1798	if (res->status & ATA_STATUS_ERROR) {
1799		if (arglist & CAM_ARG_VERBOSE) {
1800			cam_error_print(device, ccb, CAM_ESF_ALL,
1801					CAM_EPF_ALL, stderr);
1802			printf("error = 0x%02x, sector_count = 0x%04x, "
1803			       "device = 0x%02x, status = 0x%02x\n",
1804			       res->error, res->sector_count,
1805			       res->device, res->status);
1806		}
1807
1808		if (res->error & ATA_ERROR_ID_NOT_FOUND) {
1809			warnx("Max address has already been set since "
1810			      "last power-on or hardware reset");
1811		}
1812
1813		return (1);
1814	}
1815
1816	if (arglist & CAM_ARG_VERBOSE) {
1817		fprintf(stdout, "%s%d: Raw native max data:\n",
1818			device->device_name, device->dev_unit_num);
1819		/* res is 4 byte aligned */
1820		dump_data((uint16_t*)(uintptr_t)res, sizeof(struct ata_res));
1821
1822		printf("error = 0x%02x, sector_count = 0x%04x, device = 0x%02x, "
1823		       "status = 0x%02x\n", res->error, res->sector_count,
1824		       res->device, res->status);
1825	}
1826
1827	if (hpasize != NULL) {
1828		if (is48bit) {
1829			*hpasize = (((u_int64_t)((res->lba_high_exp << 16) |
1830			    (res->lba_mid_exp << 8) | res->lba_low_exp) << 24) |
1831			    ((res->lba_high << 16) | (res->lba_mid << 8) |
1832			    res->lba_low)) + 1;
1833		} else {
1834			*hpasize = (((res->device & 0x0f) << 24) |
1835			    (res->lba_high << 16) | (res->lba_mid << 8) |
1836			    res->lba_low) + 1;
1837		}
1838	}
1839
1840	return (0);
1841}
1842
1843static int
1844ata_read_native_max(struct cam_device *device, int retry_count,
1845		      u_int32_t timeout, union ccb *ccb,
1846		      struct ata_params *parm, u_int64_t *hpasize)
1847{
1848	int error;
1849	u_int cmd, is48bit;
1850	u_int8_t protocol;
1851
1852	is48bit = parm->support.command2 & ATA_SUPPORT_ADDRESS48;
1853	protocol = AP_PROTO_NON_DATA;
1854
1855	if (is48bit) {
1856		cmd = ATA_READ_NATIVE_MAX_ADDRESS48;
1857		protocol |= AP_EXTEND;
1858	} else {
1859		cmd = ATA_READ_NATIVE_MAX_ADDRESS;
1860	}
1861
1862	error = ata_do_cmd(device,
1863			   ccb,
1864			   retry_count,
1865			   /*flags*/CAM_DIR_NONE,
1866			   /*protocol*/protocol,
1867			   /*ata_flags*/AP_FLAG_CHK_COND,
1868			   /*tag_action*/MSG_SIMPLE_Q_TAG,
1869			   /*command*/cmd,
1870			   /*features*/0,
1871			   /*lba*/0,
1872			   /*sector_count*/0,
1873			   /*data_ptr*/NULL,
1874			   /*dxfer_len*/0,
1875			   timeout ? timeout : 1000,
1876			   is48bit);
1877
1878	if (error)
1879		return (error);
1880
1881	return atahpa_proc_resp(device, ccb, is48bit, hpasize);
1882}
1883
1884static int
1885atahpa_set_max(struct cam_device *device, int retry_count,
1886	      u_int32_t timeout, union ccb *ccb,
1887	      int is48bit, u_int64_t maxsize, int persist)
1888{
1889	int error;
1890	u_int cmd;
1891	u_int8_t protocol;
1892
1893	protocol = AP_PROTO_NON_DATA;
1894
1895	if (is48bit) {
1896		cmd = ATA_SET_MAX_ADDRESS48;
1897		protocol |= AP_EXTEND;
1898	} else {
1899		cmd = ATA_SET_MAX_ADDRESS;
1900	}
1901
1902	/* lba's are zero indexed so the max lba is requested max - 1 */
1903	if (maxsize)
1904		maxsize--;
1905
1906	error = ata_do_cmd(device,
1907			   ccb,
1908			   retry_count,
1909			   /*flags*/CAM_DIR_NONE,
1910			   /*protocol*/protocol,
1911			   /*ata_flags*/AP_FLAG_CHK_COND,
1912			   /*tag_action*/MSG_SIMPLE_Q_TAG,
1913			   /*command*/cmd,
1914			   /*features*/ATA_HPA_FEAT_MAX_ADDR,
1915			   /*lba*/maxsize,
1916			   /*sector_count*/persist,
1917			   /*data_ptr*/NULL,
1918			   /*dxfer_len*/0,
1919			   timeout ? timeout : 1000,
1920			   is48bit);
1921
1922	if (error)
1923		return (error);
1924
1925	return atahpa_proc_resp(device, ccb, is48bit, NULL);
1926}
1927
1928static int
1929atahpa_password(struct cam_device *device, int retry_count,
1930		u_int32_t timeout, union ccb *ccb,
1931		int is48bit, struct ata_set_max_pwd *pwd)
1932{
1933	int error;
1934	u_int cmd;
1935	u_int8_t protocol;
1936
1937	protocol = AP_PROTO_PIO_OUT;
1938	cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
1939
1940	error = ata_do_cmd(device,
1941			   ccb,
1942			   retry_count,
1943			   /*flags*/CAM_DIR_OUT,
1944			   /*protocol*/protocol,
1945			   /*ata_flags*/AP_FLAG_CHK_COND,
1946			   /*tag_action*/MSG_SIMPLE_Q_TAG,
1947			   /*command*/cmd,
1948			   /*features*/ATA_HPA_FEAT_SET_PWD,
1949			   /*lba*/0,
1950			   /*sector_count*/0,
1951			   /*data_ptr*/(u_int8_t*)pwd,
1952			   /*dxfer_len*/sizeof(struct ata_set_max_pwd),
1953			   timeout ? timeout : 1000,
1954			   is48bit);
1955
1956	if (error)
1957		return (error);
1958
1959	return atahpa_proc_resp(device, ccb, is48bit, NULL);
1960}
1961
1962static int
1963atahpa_lock(struct cam_device *device, int retry_count,
1964	    u_int32_t timeout, union ccb *ccb, int is48bit)
1965{
1966	int error;
1967	u_int cmd;
1968	u_int8_t protocol;
1969
1970	protocol = AP_PROTO_NON_DATA;
1971	cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
1972
1973	error = ata_do_cmd(device,
1974			   ccb,
1975			   retry_count,
1976			   /*flags*/CAM_DIR_NONE,
1977			   /*protocol*/protocol,
1978			   /*ata_flags*/AP_FLAG_CHK_COND,
1979			   /*tag_action*/MSG_SIMPLE_Q_TAG,
1980			   /*command*/cmd,
1981			   /*features*/ATA_HPA_FEAT_LOCK,
1982			   /*lba*/0,
1983			   /*sector_count*/0,
1984			   /*data_ptr*/NULL,
1985			   /*dxfer_len*/0,
1986			   timeout ? timeout : 1000,
1987			   is48bit);
1988
1989	if (error)
1990		return (error);
1991
1992	return atahpa_proc_resp(device, ccb, is48bit, NULL);
1993}
1994
1995static int
1996atahpa_unlock(struct cam_device *device, int retry_count,
1997	      u_int32_t timeout, union ccb *ccb,
1998	      int is48bit, struct ata_set_max_pwd *pwd)
1999{
2000	int error;
2001	u_int cmd;
2002	u_int8_t protocol;
2003
2004	protocol = AP_PROTO_PIO_OUT;
2005	cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
2006
2007	error = ata_do_cmd(device,
2008			   ccb,
2009			   retry_count,
2010			   /*flags*/CAM_DIR_OUT,
2011			   /*protocol*/protocol,
2012			   /*ata_flags*/AP_FLAG_CHK_COND,
2013			   /*tag_action*/MSG_SIMPLE_Q_TAG,
2014			   /*command*/cmd,
2015			   /*features*/ATA_HPA_FEAT_UNLOCK,
2016			   /*lba*/0,
2017			   /*sector_count*/0,
2018			   /*data_ptr*/(u_int8_t*)pwd,
2019			   /*dxfer_len*/sizeof(struct ata_set_max_pwd),
2020			   timeout ? timeout : 1000,
2021			   is48bit);
2022
2023	if (error)
2024		return (error);
2025
2026	return atahpa_proc_resp(device, ccb, is48bit, NULL);
2027}
2028
2029static int
2030atahpa_freeze_lock(struct cam_device *device, int retry_count,
2031		   u_int32_t timeout, union ccb *ccb, int is48bit)
2032{
2033	int error;
2034	u_int cmd;
2035	u_int8_t protocol;
2036
2037	protocol = AP_PROTO_NON_DATA;
2038	cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
2039
2040	error = ata_do_cmd(device,
2041			   ccb,
2042			   retry_count,
2043			   /*flags*/CAM_DIR_NONE,
2044			   /*protocol*/protocol,
2045			   /*ata_flags*/AP_FLAG_CHK_COND,
2046			   /*tag_action*/MSG_SIMPLE_Q_TAG,
2047			   /*command*/cmd,
2048			   /*features*/ATA_HPA_FEAT_FREEZE,
2049			   /*lba*/0,
2050			   /*sector_count*/0,
2051			   /*data_ptr*/NULL,
2052			   /*dxfer_len*/0,
2053			   timeout ? timeout : 1000,
2054			   is48bit);
2055
2056	if (error)
2057		return (error);
2058
2059	return atahpa_proc_resp(device, ccb, is48bit, NULL);
2060}
2061
2062
2063int
2064ata_do_identify(struct cam_device *device, int retry_count, int timeout,
2065		union ccb *ccb, struct ata_params** ident_bufp)
2066{
2067	struct ata_params *ident_buf;
2068	struct ccb_pathinq cpi;
2069	struct ccb_getdev cgd;
2070	u_int i, error;
2071	int16_t *ptr;
2072	u_int8_t command, retry_command;
2073
2074	if (get_cpi(device, &cpi) != 0) {
2075		warnx("couldn't get CPI");
2076		return (-1);
2077	}
2078
2079	/* Neither PROTO_ATAPI or PROTO_SATAPM are used in cpi.protocol */
2080	if (cpi.protocol == PROTO_ATA) {
2081		if (get_cgd(device, &cgd) != 0) {
2082			warnx("couldn't get CGD");
2083			return (-1);
2084		}
2085
2086		command = (cgd.protocol == PROTO_ATA) ?
2087		    ATA_ATA_IDENTIFY : ATA_ATAPI_IDENTIFY;
2088		retry_command = 0;
2089	} else {
2090		/* We don't know which for sure so try both */
2091		command = ATA_ATA_IDENTIFY;
2092		retry_command = ATA_ATAPI_IDENTIFY;
2093	}
2094
2095	ptr = (uint16_t *)calloc(1, sizeof(struct ata_params));
2096	if (ptr == NULL) {
2097		warnx("can't calloc memory for identify\n");
2098		return (1);
2099	}
2100
2101	error = ata_do_28bit_cmd(device,
2102				 ccb,
2103				 /*retries*/retry_count,
2104				 /*flags*/CAM_DIR_IN,
2105				 /*protocol*/AP_PROTO_PIO_IN,
2106				 /*tag_action*/MSG_SIMPLE_Q_TAG,
2107				 /*command*/command,
2108				 /*features*/0,
2109				 /*lba*/0,
2110				 /*sector_count*/(u_int8_t)sizeof(struct ata_params),
2111				 /*data_ptr*/(u_int8_t *)ptr,
2112				 /*dxfer_len*/sizeof(struct ata_params),
2113				 /*timeout*/timeout ? timeout : 30 * 1000,
2114				 /*quiet*/1);
2115
2116	if (error != 0) {
2117		if (retry_command == 0) {
2118			free(ptr);
2119			return (1);
2120		}
2121		error = ata_do_28bit_cmd(device,
2122					 ccb,
2123					 /*retries*/retry_count,
2124					 /*flags*/CAM_DIR_IN,
2125					 /*protocol*/AP_PROTO_PIO_IN,
2126					 /*tag_action*/MSG_SIMPLE_Q_TAG,
2127					 /*command*/retry_command,
2128					 /*features*/0,
2129					 /*lba*/0,
2130					 /*sector_count*/(u_int8_t)
2131					     sizeof(struct ata_params),
2132					 /*data_ptr*/(u_int8_t *)ptr,
2133					 /*dxfer_len*/sizeof(struct ata_params),
2134					 /*timeout*/timeout ? timeout : 30 * 1000,
2135					 /*quiet*/0);
2136
2137		if (error != 0) {
2138			free(ptr);
2139			return (1);
2140		}
2141	}
2142
2143	error = 1;
2144	for (i = 0; i < sizeof(struct ata_params) / 2; i++) {
2145		ptr[i] = le16toh(ptr[i]);
2146		if (ptr[i] != 0)
2147			error = 0;
2148	}
2149
2150	if (arglist & CAM_ARG_VERBOSE) {
2151		fprintf(stdout, "%s%d: Raw identify data:\n",
2152		    device->device_name, device->dev_unit_num);
2153		dump_data(ptr, sizeof(struct ata_params));
2154	}
2155
2156	/* check for invalid (all zero) response */
2157	if (error != 0) {
2158		warnx("Invalid identify response detected");
2159		free(ptr);
2160		return (error);
2161	}
2162
2163	ident_buf = (struct ata_params *)ptr;
2164	if (strncmp(ident_buf->model, "FX", 2) &&
2165	    strncmp(ident_buf->model, "NEC", 3) &&
2166	    strncmp(ident_buf->model, "Pioneer", 7) &&
2167	    strncmp(ident_buf->model, "SHARP", 5)) {
2168		ata_bswap(ident_buf->model, sizeof(ident_buf->model));
2169		ata_bswap(ident_buf->revision, sizeof(ident_buf->revision));
2170		ata_bswap(ident_buf->serial, sizeof(ident_buf->serial));
2171		ata_bswap(ident_buf->media_serial, sizeof(ident_buf->media_serial));
2172	}
2173	ata_btrim(ident_buf->model, sizeof(ident_buf->model));
2174	ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model));
2175	ata_btrim(ident_buf->revision, sizeof(ident_buf->revision));
2176	ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision));
2177	ata_btrim(ident_buf->serial, sizeof(ident_buf->serial));
2178	ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial));
2179	ata_btrim(ident_buf->media_serial, sizeof(ident_buf->media_serial));
2180	ata_bpack(ident_buf->media_serial, ident_buf->media_serial,
2181	    sizeof(ident_buf->media_serial));
2182
2183	*ident_bufp = ident_buf;
2184
2185	return (0);
2186}
2187
2188
2189static int
2190ataidentify(struct cam_device *device, int retry_count, int timeout)
2191{
2192	union ccb *ccb;
2193	struct ata_params *ident_buf;
2194	u_int64_t hpasize;
2195
2196	if ((ccb = cam_getccb(device)) == NULL) {
2197		warnx("couldn't allocate CCB");
2198		return (1);
2199	}
2200
2201	if (ata_do_identify(device, retry_count, timeout, ccb, &ident_buf) != 0) {
2202		cam_freeccb(ccb);
2203		return (1);
2204	}
2205
2206	if (ident_buf->support.command1 & ATA_SUPPORT_PROTECTED) {
2207		if (ata_read_native_max(device, retry_count, timeout, ccb,
2208					ident_buf, &hpasize) != 0) {
2209			cam_freeccb(ccb);
2210			return (1);
2211		}
2212	} else {
2213		hpasize = 0;
2214	}
2215
2216	printf("%s%d: ", device->device_name, device->dev_unit_num);
2217	ata_print_ident(ident_buf);
2218	camxferrate(device);
2219	atacapprint(ident_buf);
2220	atahpa_print(ident_buf, hpasize, 0);
2221
2222	free(ident_buf);
2223	cam_freeccb(ccb);
2224
2225	return (0);
2226}
2227#endif /* MINIMALISTIC */
2228
2229
2230#ifndef MINIMALISTIC
2231enum {
2232	ATA_SECURITY_ACTION_PRINT,
2233	ATA_SECURITY_ACTION_FREEZE,
2234	ATA_SECURITY_ACTION_UNLOCK,
2235	ATA_SECURITY_ACTION_DISABLE,
2236	ATA_SECURITY_ACTION_ERASE,
2237	ATA_SECURITY_ACTION_ERASE_ENHANCED,
2238	ATA_SECURITY_ACTION_SET_PASSWORD
2239};
2240
2241static void
2242atasecurity_print_time(u_int16_t tw)
2243{
2244
2245	if (tw == 0)
2246		printf("unspecified");
2247	else if (tw >= 255)
2248		printf("> 508 min");
2249	else
2250		printf("%i min", 2 * tw);
2251}
2252
2253static u_int32_t
2254atasecurity_erase_timeout_msecs(u_int16_t timeout)
2255{
2256
2257	if (timeout == 0)
2258		return 2 * 3600 * 1000; /* default: two hours */
2259	else if (timeout > 255)
2260		return (508 + 60) * 60 * 1000; /* spec says > 508 minutes */
2261
2262	return ((2 * timeout) + 5) * 60 * 1000; /* add a 5min margin */
2263}
2264
2265
2266static void
2267atasecurity_notify(u_int8_t command, struct ata_security_password *pwd)
2268{
2269	struct ata_cmd cmd;
2270
2271	bzero(&cmd, sizeof(cmd));
2272	cmd.command = command;
2273	printf("Issuing %s", ata_op_string(&cmd));
2274
2275	if (pwd != NULL) {
2276		char pass[sizeof(pwd->password)+1];
2277
2278		/* pwd->password may not be null terminated */
2279		pass[sizeof(pwd->password)] = '\0';
2280		strncpy(pass, pwd->password, sizeof(pwd->password));
2281		printf(" password='%s', user='%s'",
2282			pass,
2283			(pwd->ctrl & ATA_SECURITY_PASSWORD_MASTER) ?
2284			"master" : "user");
2285
2286		if (command == ATA_SECURITY_SET_PASSWORD) {
2287			printf(", mode='%s'",
2288			       (pwd->ctrl & ATA_SECURITY_LEVEL_MAXIMUM) ?
2289			       "maximum" : "high");
2290		}
2291	}
2292
2293	printf("\n");
2294}
2295
2296static int
2297atasecurity_freeze(struct cam_device *device, union ccb *ccb,
2298		   int retry_count, u_int32_t timeout, int quiet)
2299{
2300
2301	if (quiet == 0)
2302		atasecurity_notify(ATA_SECURITY_FREEZE_LOCK, NULL);
2303
2304	return ata_do_28bit_cmd(device,
2305				ccb,
2306				retry_count,
2307				/*flags*/CAM_DIR_NONE,
2308				/*protocol*/AP_PROTO_NON_DATA,
2309				/*tag_action*/MSG_SIMPLE_Q_TAG,
2310				/*command*/ATA_SECURITY_FREEZE_LOCK,
2311				/*features*/0,
2312				/*lba*/0,
2313				/*sector_count*/0,
2314				/*data_ptr*/NULL,
2315				/*dxfer_len*/0,
2316				/*timeout*/timeout,
2317				/*quiet*/0);
2318}
2319
2320static int
2321atasecurity_unlock(struct cam_device *device, union ccb *ccb,
2322		   int retry_count, u_int32_t timeout,
2323		   struct ata_security_password *pwd, int quiet)
2324{
2325
2326	if (quiet == 0)
2327		atasecurity_notify(ATA_SECURITY_UNLOCK, pwd);
2328
2329	return ata_do_28bit_cmd(device,
2330				ccb,
2331				retry_count,
2332				/*flags*/CAM_DIR_OUT,
2333				/*protocol*/AP_PROTO_PIO_OUT,
2334				/*tag_action*/MSG_SIMPLE_Q_TAG,
2335				/*command*/ATA_SECURITY_UNLOCK,
2336				/*features*/0,
2337				/*lba*/0,
2338				/*sector_count*/0,
2339				/*data_ptr*/(u_int8_t *)pwd,
2340				/*dxfer_len*/sizeof(*pwd),
2341				/*timeout*/timeout,
2342				/*quiet*/0);
2343}
2344
2345static int
2346atasecurity_disable(struct cam_device *device, union ccb *ccb,
2347		    int retry_count, u_int32_t timeout,
2348		    struct ata_security_password *pwd, int quiet)
2349{
2350
2351	if (quiet == 0)
2352		atasecurity_notify(ATA_SECURITY_DISABLE_PASSWORD, pwd);
2353	return ata_do_28bit_cmd(device,
2354				ccb,
2355				retry_count,
2356				/*flags*/CAM_DIR_OUT,
2357				/*protocol*/AP_PROTO_PIO_OUT,
2358				/*tag_action*/MSG_SIMPLE_Q_TAG,
2359				/*command*/ATA_SECURITY_DISABLE_PASSWORD,
2360				/*features*/0,
2361				/*lba*/0,
2362				/*sector_count*/0,
2363				/*data_ptr*/(u_int8_t *)pwd,
2364				/*dxfer_len*/sizeof(*pwd),
2365				/*timeout*/timeout,
2366				/*quiet*/0);
2367}
2368
2369
2370static int
2371atasecurity_erase_confirm(struct cam_device *device,
2372			  struct ata_params* ident_buf)
2373{
2374
2375	printf("\nYou are about to ERASE ALL DATA from the following"
2376	       " device:\n%s%d,%s%d: ", device->device_name,
2377	       device->dev_unit_num, device->given_dev_name,
2378	       device->given_unit_number);
2379	ata_print_ident(ident_buf);
2380
2381	for(;;) {
2382		char str[50];
2383		printf("\nAre you SURE you want to ERASE ALL DATA? (yes/no) ");
2384
2385		if (fgets(str, sizeof(str), stdin) != NULL) {
2386			if (strncasecmp(str, "yes", 3) == 0) {
2387				return (1);
2388			} else if (strncasecmp(str, "no", 2) == 0) {
2389				return (0);
2390			} else {
2391				printf("Please answer \"yes\" or "
2392				       "\"no\"\n");
2393			}
2394		}
2395	}
2396
2397	/* NOTREACHED */
2398	return (0);
2399}
2400
2401static int
2402atasecurity_erase(struct cam_device *device, union ccb *ccb,
2403		  int retry_count, u_int32_t timeout,
2404		  u_int32_t erase_timeout,
2405		  struct ata_security_password *pwd, int quiet)
2406{
2407	int error;
2408
2409	if (quiet == 0)
2410		atasecurity_notify(ATA_SECURITY_ERASE_PREPARE, NULL);
2411
2412	error = ata_do_28bit_cmd(device,
2413				 ccb,
2414				 retry_count,
2415				 /*flags*/CAM_DIR_NONE,
2416				 /*protocol*/AP_PROTO_NON_DATA,
2417				 /*tag_action*/MSG_SIMPLE_Q_TAG,
2418				 /*command*/ATA_SECURITY_ERASE_PREPARE,
2419				 /*features*/0,
2420				 /*lba*/0,
2421				 /*sector_count*/0,
2422				 /*data_ptr*/NULL,
2423				 /*dxfer_len*/0,
2424				 /*timeout*/timeout,
2425				 /*quiet*/0);
2426
2427	if (error != 0)
2428		return error;
2429
2430	if (quiet == 0)
2431		atasecurity_notify(ATA_SECURITY_ERASE_UNIT, pwd);
2432
2433	error = ata_do_28bit_cmd(device,
2434				 ccb,
2435				 retry_count,
2436				 /*flags*/CAM_DIR_OUT,
2437				 /*protocol*/AP_PROTO_PIO_OUT,
2438				 /*tag_action*/MSG_SIMPLE_Q_TAG,
2439				 /*command*/ATA_SECURITY_ERASE_UNIT,
2440				 /*features*/0,
2441				 /*lba*/0,
2442				 /*sector_count*/0,
2443				 /*data_ptr*/(u_int8_t *)pwd,
2444				 /*dxfer_len*/sizeof(*pwd),
2445				 /*timeout*/erase_timeout,
2446				 /*quiet*/0);
2447
2448	if (error == 0 && quiet == 0)
2449		printf("\nErase Complete\n");
2450
2451	return error;
2452}
2453
2454static int
2455atasecurity_set_password(struct cam_device *device, union ccb *ccb,
2456			 int retry_count, u_int32_t timeout,
2457			 struct ata_security_password *pwd, int quiet)
2458{
2459
2460	if (quiet == 0)
2461		atasecurity_notify(ATA_SECURITY_SET_PASSWORD, pwd);
2462
2463	return ata_do_28bit_cmd(device,
2464				 ccb,
2465				 retry_count,
2466				 /*flags*/CAM_DIR_OUT,
2467				 /*protocol*/AP_PROTO_PIO_OUT,
2468				 /*tag_action*/MSG_SIMPLE_Q_TAG,
2469				 /*command*/ATA_SECURITY_SET_PASSWORD,
2470				 /*features*/0,
2471				 /*lba*/0,
2472				 /*sector_count*/0,
2473				 /*data_ptr*/(u_int8_t *)pwd,
2474				 /*dxfer_len*/sizeof(*pwd),
2475				 /*timeout*/timeout,
2476				 /*quiet*/0);
2477}
2478
2479static void
2480atasecurity_print(struct ata_params *parm)
2481{
2482
2483	printf("\nSecurity Option           Value\n");
2484	if (arglist & CAM_ARG_VERBOSE) {
2485		printf("status                    %04x\n",
2486		       parm->security_status);
2487	}
2488	printf("supported                 %s\n",
2489		parm->security_status & ATA_SECURITY_SUPPORTED ? "yes" : "no");
2490	if (!(parm->security_status & ATA_SECURITY_SUPPORTED))
2491		return;
2492	printf("enabled                   %s\n",
2493		parm->security_status & ATA_SECURITY_ENABLED ? "yes" : "no");
2494	printf("drive locked              %s\n",
2495		parm->security_status & ATA_SECURITY_LOCKED ? "yes" : "no");
2496	printf("security config frozen    %s\n",
2497		parm->security_status & ATA_SECURITY_FROZEN ? "yes" : "no");
2498	printf("count expired             %s\n",
2499		parm->security_status & ATA_SECURITY_COUNT_EXP ? "yes" : "no");
2500	printf("security level            %s\n",
2501		parm->security_status & ATA_SECURITY_LEVEL ? "maximum" : "high");
2502	printf("enhanced erase supported  %s\n",
2503		parm->security_status & ATA_SECURITY_ENH_SUPP ? "yes" : "no");
2504	printf("erase time                ");
2505	atasecurity_print_time(parm->erase_time);
2506	printf("\n");
2507	printf("enhanced erase time       ");
2508	atasecurity_print_time(parm->enhanced_erase_time);
2509	printf("\n");
2510	printf("master password rev       %04x%s\n",
2511		parm->master_passwd_revision,
2512		parm->master_passwd_revision == 0x0000 ||
2513		parm->master_passwd_revision == 0xFFFF ?  " (unsupported)" : "");
2514}
2515
2516/*
2517 * Validates and copies the password in optarg to the passed buffer.
2518 * If the password in optarg is the same length as the buffer then
2519 * the data will still be copied but no null termination will occur.
2520 */
2521static int
2522ata_getpwd(u_int8_t *passwd, int max, char opt)
2523{
2524	int len;
2525
2526	len = strlen(optarg);
2527	if (len > max) {
2528		warnx("-%c password is too long", opt);
2529		return (1);
2530	} else if (len == 0) {
2531		warnx("-%c password is missing", opt);
2532		return (1);
2533	} else if (optarg[0] == '-'){
2534		warnx("-%c password starts with '-' (generic arg?)", opt);
2535		return (1);
2536	} else if (strlen(passwd) != 0 && strcmp(passwd, optarg) != 0) {
2537		warnx("-%c password conflicts with existing password from -%c",
2538		      opt, pwd_opt);
2539		return (1);
2540	}
2541
2542	/* Callers pass in a buffer which does NOT need to be terminated */
2543	strncpy(passwd, optarg, max);
2544	pwd_opt = opt;
2545
2546	return (0);
2547}
2548
2549enum {
2550	ATA_HPA_ACTION_PRINT,
2551	ATA_HPA_ACTION_SET_MAX,
2552	ATA_HPA_ACTION_SET_PWD,
2553	ATA_HPA_ACTION_LOCK,
2554	ATA_HPA_ACTION_UNLOCK,
2555	ATA_HPA_ACTION_FREEZE_LOCK
2556};
2557
2558static int
2559atahpa_set_confirm(struct cam_device *device, struct ata_params* ident_buf,
2560		   u_int64_t maxsize, int persist)
2561{
2562	printf("\nYou are about to configure HPA to limit the user accessible\n"
2563	       "sectors to %ju %s on the device:\n%s%d,%s%d: ", maxsize,
2564	       persist ? "persistently" : "temporarily",
2565	       device->device_name, device->dev_unit_num,
2566	       device->given_dev_name, device->given_unit_number);
2567	ata_print_ident(ident_buf);
2568
2569	for(;;) {
2570		char str[50];
2571		printf("\nAre you SURE you want to configure HPA? (yes/no) ");
2572
2573		if (NULL != fgets(str, sizeof(str), stdin)) {
2574			if (0 == strncasecmp(str, "yes", 3)) {
2575				return (1);
2576			} else if (0 == strncasecmp(str, "no", 2)) {
2577				return (0);
2578			} else {
2579				printf("Please answer \"yes\" or "
2580				       "\"no\"\n");
2581			}
2582		}
2583	}
2584
2585	/* NOTREACHED */
2586	return (0);
2587}
2588
2589static int
2590atahpa(struct cam_device *device, int retry_count, int timeout,
2591       int argc, char **argv, char *combinedopt)
2592{
2593	union ccb *ccb;
2594	struct ata_params *ident_buf;
2595	struct ccb_getdev cgd;
2596	struct ata_set_max_pwd pwd;
2597	int error, confirm, quiet, c, action, actions, setpwd, persist;
2598	int security, is48bit, pwdsize;
2599	u_int64_t hpasize, maxsize;
2600
2601	actions = 0;
2602	setpwd = 0;
2603	confirm = 0;
2604	quiet = 0;
2605	maxsize = 0;
2606	persist = 0;
2607	security = 0;
2608
2609	memset(&pwd, 0, sizeof(pwd));
2610
2611	/* default action is to print hpa information */
2612	action = ATA_HPA_ACTION_PRINT;
2613	pwdsize = sizeof(pwd.password);
2614
2615	while ((c = getopt(argc, argv, combinedopt)) != -1) {
2616		switch(c){
2617		case 's':
2618			action = ATA_HPA_ACTION_SET_MAX;
2619			maxsize = strtoumax(optarg, NULL, 0);
2620			actions++;
2621			break;
2622
2623		case 'p':
2624			if (ata_getpwd(pwd.password, pwdsize, c) != 0)
2625				return (1);
2626			action = ATA_HPA_ACTION_SET_PWD;
2627			security = 1;
2628			actions++;
2629			break;
2630
2631		case 'l':
2632			action = ATA_HPA_ACTION_LOCK;
2633			security = 1;
2634			actions++;
2635			break;
2636
2637		case 'U':
2638			if (ata_getpwd(pwd.password, pwdsize, c) != 0)
2639				return (1);
2640			action = ATA_HPA_ACTION_UNLOCK;
2641			security = 1;
2642			actions++;
2643			break;
2644
2645		case 'f':
2646			action = ATA_HPA_ACTION_FREEZE_LOCK;
2647			security = 1;
2648			actions++;
2649			break;
2650
2651		case 'P':
2652			persist = 1;
2653			break;
2654
2655		case 'y':
2656			confirm++;
2657			break;
2658
2659		case 'q':
2660			quiet++;
2661			break;
2662		}
2663	}
2664
2665	if (actions > 1) {
2666		warnx("too many hpa actions specified");
2667		return (1);
2668	}
2669
2670	if (get_cgd(device, &cgd) != 0) {
2671		warnx("couldn't get CGD");
2672		return (1);
2673	}
2674
2675	ccb = cam_getccb(device);
2676	if (ccb == NULL) {
2677		warnx("couldn't allocate CCB");
2678		return (1);
2679	}
2680
2681	error = ata_do_identify(device, retry_count, timeout, ccb, &ident_buf);
2682	if (error != 0) {
2683		cam_freeccb(ccb);
2684		return (1);
2685	}
2686
2687	if (quiet == 0) {
2688		printf("%s%d: ", device->device_name, device->dev_unit_num);
2689		ata_print_ident(ident_buf);
2690		camxferrate(device);
2691	}
2692
2693	if (action == ATA_HPA_ACTION_PRINT) {
2694		error = ata_read_native_max(device, retry_count, timeout, ccb,
2695					    ident_buf, &hpasize);
2696		if (error == 0)
2697			atahpa_print(ident_buf, hpasize, 1);
2698
2699		cam_freeccb(ccb);
2700		free(ident_buf);
2701		return (error);
2702	}
2703
2704	if (!(ident_buf->support.command1 & ATA_SUPPORT_PROTECTED)) {
2705		warnx("HPA is not supported by this device");
2706		cam_freeccb(ccb);
2707		free(ident_buf);
2708		return (1);
2709	}
2710
2711	if (security && !(ident_buf->support.command1 & ATA_SUPPORT_MAXSECURITY)) {
2712		warnx("HPA Security is not supported by this device");
2713		cam_freeccb(ccb);
2714		free(ident_buf);
2715		return (1);
2716	}
2717
2718	is48bit = ident_buf->support.command2 & ATA_SUPPORT_ADDRESS48;
2719
2720	/*
2721	 * The ATA spec requires:
2722	 * 1. Read native max addr is called directly before set max addr
2723	 * 2. Read native max addr is NOT called before any other set max call
2724	 */
2725	switch(action) {
2726	case ATA_HPA_ACTION_SET_MAX:
2727		if (confirm == 0 &&
2728		    atahpa_set_confirm(device, ident_buf, maxsize,
2729		    persist) == 0) {
2730			cam_freeccb(ccb);
2731			free(ident_buf);
2732			return (1);
2733		}
2734
2735		error = ata_read_native_max(device, retry_count, timeout,
2736					    ccb, ident_buf, &hpasize);
2737		if (error == 0) {
2738			error = atahpa_set_max(device, retry_count, timeout,
2739					       ccb, is48bit, maxsize, persist);
2740			if (error == 0) {
2741				/* redo identify to get new lba values */
2742				error = ata_do_identify(device, retry_count,
2743							timeout, ccb,
2744							&ident_buf);
2745				atahpa_print(ident_buf, hpasize, 1);
2746			}
2747		}
2748		break;
2749
2750	case ATA_HPA_ACTION_SET_PWD:
2751		error = atahpa_password(device, retry_count, timeout,
2752					ccb, is48bit, &pwd);
2753		if (error == 0)
2754			printf("HPA password has been set\n");
2755		break;
2756
2757	case ATA_HPA_ACTION_LOCK:
2758		error = atahpa_lock(device, retry_count, timeout,
2759				    ccb, is48bit);
2760		if (error == 0)
2761			printf("HPA has been locked\n");
2762		break;
2763
2764	case ATA_HPA_ACTION_UNLOCK:
2765		error = atahpa_unlock(device, retry_count, timeout,
2766				      ccb, is48bit, &pwd);
2767		if (error == 0)
2768			printf("HPA has been unlocked\n");
2769		break;
2770
2771	case ATA_HPA_ACTION_FREEZE_LOCK:
2772		error = atahpa_freeze_lock(device, retry_count, timeout,
2773					   ccb, is48bit);
2774		if (error == 0)
2775			printf("HPA has been frozen\n");
2776		break;
2777
2778	default:
2779		errx(1, "Option currently not supported");
2780	}
2781
2782	cam_freeccb(ccb);
2783	free(ident_buf);
2784
2785	return (error);
2786}
2787
2788static int
2789atasecurity(struct cam_device *device, int retry_count, int timeout,
2790	    int argc, char **argv, char *combinedopt)
2791{
2792	union ccb *ccb;
2793	struct ata_params *ident_buf;
2794	int error, confirm, quiet, c, action, actions, setpwd;
2795	int security_enabled, erase_timeout, pwdsize;
2796	struct ata_security_password pwd;
2797
2798	actions = 0;
2799	setpwd = 0;
2800	erase_timeout = 0;
2801	confirm = 0;
2802	quiet = 0;
2803
2804	memset(&pwd, 0, sizeof(pwd));
2805
2806	/* default action is to print security information */
2807	action = ATA_SECURITY_ACTION_PRINT;
2808
2809	/* user is master by default as its safer that way */
2810	pwd.ctrl |= ATA_SECURITY_PASSWORD_MASTER;
2811	pwdsize = sizeof(pwd.password);
2812
2813	while ((c = getopt(argc, argv, combinedopt)) != -1) {
2814		switch(c){
2815		case 'f':
2816			action = ATA_SECURITY_ACTION_FREEZE;
2817			actions++;
2818			break;
2819
2820		case 'U':
2821			if (strcasecmp(optarg, "user") == 0) {
2822				pwd.ctrl |= ATA_SECURITY_PASSWORD_USER;
2823				pwd.ctrl &= ~ATA_SECURITY_PASSWORD_MASTER;
2824			} else if (strcasecmp(optarg, "master") == 0) {
2825				pwd.ctrl |= ATA_SECURITY_PASSWORD_MASTER;
2826				pwd.ctrl &= ~ATA_SECURITY_PASSWORD_USER;
2827			} else {
2828				warnx("-U argument '%s' is invalid (must be "
2829				      "'user' or 'master')", optarg);
2830				return (1);
2831			}
2832			break;
2833
2834		case 'l':
2835			if (strcasecmp(optarg, "high") == 0) {
2836				pwd.ctrl |= ATA_SECURITY_LEVEL_HIGH;
2837				pwd.ctrl &= ~ATA_SECURITY_LEVEL_MAXIMUM;
2838			} else if (strcasecmp(optarg, "maximum") == 0) {
2839				pwd.ctrl |= ATA_SECURITY_LEVEL_MAXIMUM;
2840				pwd.ctrl &= ~ATA_SECURITY_LEVEL_HIGH;
2841			} else {
2842				warnx("-l argument '%s' is unknown (must be "
2843				      "'high' or 'maximum')", optarg);
2844				return (1);
2845			}
2846			break;
2847
2848		case 'k':
2849			if (ata_getpwd(pwd.password, pwdsize, c) != 0)
2850				return (1);
2851			action = ATA_SECURITY_ACTION_UNLOCK;
2852			actions++;
2853			break;
2854
2855		case 'd':
2856			if (ata_getpwd(pwd.password, pwdsize, c) != 0)
2857				return (1);
2858			action = ATA_SECURITY_ACTION_DISABLE;
2859			actions++;
2860			break;
2861
2862		case 'e':
2863			if (ata_getpwd(pwd.password, pwdsize, c) != 0)
2864				return (1);
2865			action = ATA_SECURITY_ACTION_ERASE;
2866			actions++;
2867			break;
2868
2869		case 'h':
2870			if (ata_getpwd(pwd.password, pwdsize, c) != 0)
2871				return (1);
2872			pwd.ctrl |= ATA_SECURITY_ERASE_ENHANCED;
2873			action = ATA_SECURITY_ACTION_ERASE_ENHANCED;
2874			actions++;
2875			break;
2876
2877		case 's':
2878			if (ata_getpwd(pwd.password, pwdsize, c) != 0)
2879				return (1);
2880			setpwd = 1;
2881			if (action == ATA_SECURITY_ACTION_PRINT)
2882				action = ATA_SECURITY_ACTION_SET_PASSWORD;
2883			/*
2884			 * Don't increment action as this can be combined
2885			 * with other actions.
2886			 */
2887			break;
2888
2889		case 'y':
2890			confirm++;
2891			break;
2892
2893		case 'q':
2894			quiet++;
2895			break;
2896
2897		case 'T':
2898			erase_timeout = atoi(optarg) * 1000;
2899			break;
2900		}
2901	}
2902
2903	if (actions > 1) {
2904		warnx("too many security actions specified");
2905		return (1);
2906	}
2907
2908	if ((ccb = cam_getccb(device)) == NULL) {
2909		warnx("couldn't allocate CCB");
2910		return (1);
2911	}
2912
2913	error = ata_do_identify(device, retry_count, timeout, ccb, &ident_buf);
2914	if (error != 0) {
2915		cam_freeccb(ccb);
2916		return (1);
2917	}
2918
2919	if (quiet == 0) {
2920		printf("%s%d: ", device->device_name, device->dev_unit_num);
2921		ata_print_ident(ident_buf);
2922		camxferrate(device);
2923	}
2924
2925	if (action == ATA_SECURITY_ACTION_PRINT) {
2926		atasecurity_print(ident_buf);
2927		free(ident_buf);
2928		cam_freeccb(ccb);
2929		return (0);
2930	}
2931
2932	if ((ident_buf->support.command1 & ATA_SUPPORT_SECURITY) == 0) {
2933		warnx("Security not supported");
2934		free(ident_buf);
2935		cam_freeccb(ccb);
2936		return (1);
2937	}
2938
2939	/* default timeout 15 seconds the same as linux hdparm */
2940	timeout = timeout ? timeout : 15 * 1000;
2941
2942	security_enabled = ident_buf->security_status & ATA_SECURITY_ENABLED;
2943
2944	/* first set the password if requested */
2945	if (setpwd == 1) {
2946		/* confirm we can erase before setting the password if erasing */
2947		if (confirm == 0 &&
2948		    (action == ATA_SECURITY_ACTION_ERASE_ENHANCED ||
2949		    action == ATA_SECURITY_ACTION_ERASE) &&
2950		    atasecurity_erase_confirm(device, ident_buf) == 0) {
2951			cam_freeccb(ccb);
2952			free(ident_buf);
2953			return (error);
2954		}
2955
2956		if (pwd.ctrl & ATA_SECURITY_PASSWORD_MASTER) {
2957			pwd.revision = ident_buf->master_passwd_revision;
2958			if (pwd.revision != 0 && pwd.revision != 0xfff &&
2959			    --pwd.revision == 0) {
2960				pwd.revision = 0xfffe;
2961			}
2962		}
2963		error = atasecurity_set_password(device, ccb, retry_count,
2964						 timeout, &pwd, quiet);
2965		if (error != 0) {
2966			cam_freeccb(ccb);
2967			free(ident_buf);
2968			return (error);
2969		}
2970		security_enabled = 1;
2971	}
2972
2973	switch(action) {
2974	case ATA_SECURITY_ACTION_FREEZE:
2975		error = atasecurity_freeze(device, ccb, retry_count,
2976					   timeout, quiet);
2977		break;
2978
2979	case ATA_SECURITY_ACTION_UNLOCK:
2980		if (security_enabled) {
2981			if (ident_buf->security_status & ATA_SECURITY_LOCKED) {
2982				error = atasecurity_unlock(device, ccb,
2983					retry_count, timeout, &pwd, quiet);
2984			} else {
2985				warnx("Can't unlock, drive is not locked");
2986				error = 1;
2987			}
2988		} else {
2989			warnx("Can't unlock, security is disabled");
2990			error = 1;
2991		}
2992		break;
2993
2994	case ATA_SECURITY_ACTION_DISABLE:
2995		if (security_enabled) {
2996			/* First unlock the drive if its locked */
2997			if (ident_buf->security_status & ATA_SECURITY_LOCKED) {
2998				error = atasecurity_unlock(device, ccb,
2999							   retry_count,
3000							   timeout,
3001							   &pwd,
3002							   quiet);
3003			}
3004
3005			if (error == 0) {
3006				error = atasecurity_disable(device,
3007							    ccb,
3008							    retry_count,
3009							    timeout,
3010							    &pwd,
3011							    quiet);
3012			}
3013		} else {
3014			warnx("Can't disable security (already disabled)");
3015			error = 1;
3016		}
3017		break;
3018
3019	case ATA_SECURITY_ACTION_ERASE:
3020		if (security_enabled) {
3021			if (erase_timeout == 0) {
3022				erase_timeout = atasecurity_erase_timeout_msecs(
3023				    ident_buf->erase_time);
3024			}
3025
3026			error = atasecurity_erase(device, ccb, retry_count,
3027					          timeout, erase_timeout, &pwd,
3028						  quiet);
3029		} else {
3030			warnx("Can't secure erase (security is disabled)");
3031			error = 1;
3032		}
3033		break;
3034
3035	case ATA_SECURITY_ACTION_ERASE_ENHANCED:
3036		if (security_enabled) {
3037			if (ident_buf->security_status & ATA_SECURITY_ENH_SUPP) {
3038				if (erase_timeout == 0) {
3039					erase_timeout =
3040					    atasecurity_erase_timeout_msecs(
3041						ident_buf->enhanced_erase_time);
3042				}
3043
3044				error = atasecurity_erase(device, ccb,
3045							  retry_count, timeout,
3046							  erase_timeout, &pwd,
3047							  quiet);
3048			} else {
3049				warnx("Enhanced erase is not supported");
3050				error = 1;
3051			}
3052		} else {
3053			warnx("Can't secure erase (enhanced), "
3054			      "(security is disabled)");
3055			error = 1;
3056		}
3057		break;
3058	}
3059
3060	cam_freeccb(ccb);
3061	free(ident_buf);
3062
3063	return (error);
3064}
3065#endif /* MINIMALISTIC */
3066
3067/*
3068 * Parse out a bus, or a bus, target and lun in the following
3069 * format:
3070 * bus
3071 * bus:target
3072 * bus:target:lun
3073 *
3074 * Returns the number of parsed components, or 0.
3075 */
3076static int
3077parse_btl(char *tstr, path_id_t *bus, target_id_t *target, lun_id_t *lun,
3078    cam_argmask *arglst)
3079{
3080	char *tmpstr;
3081	int convs = 0;
3082
3083	while (isspace(*tstr) && (*tstr != '\0'))
3084		tstr++;
3085
3086	tmpstr = (char *)strtok(tstr, ":");
3087	if ((tmpstr != NULL) && (*tmpstr != '\0')) {
3088		*bus = strtol(tmpstr, NULL, 0);
3089		*arglst |= CAM_ARG_BUS;
3090		convs++;
3091		tmpstr = (char *)strtok(NULL, ":");
3092		if ((tmpstr != NULL) && (*tmpstr != '\0')) {
3093			*target = strtol(tmpstr, NULL, 0);
3094			*arglst |= CAM_ARG_TARGET;
3095			convs++;
3096			tmpstr = (char *)strtok(NULL, ":");
3097			if ((tmpstr != NULL) && (*tmpstr != '\0')) {
3098				*lun = strtol(tmpstr, NULL, 0);
3099				*arglst |= CAM_ARG_LUN;
3100				convs++;
3101			}
3102		}
3103	}
3104
3105	return convs;
3106}
3107
3108static int
3109dorescan_or_reset(int argc, char **argv, int rescan)
3110{
3111	static const char must[] =
3112		"you must specify \"all\", a bus, or a bus:target:lun to %s";
3113	int rv, error = 0;
3114	path_id_t bus = CAM_BUS_WILDCARD;
3115	target_id_t target = CAM_TARGET_WILDCARD;
3116	lun_id_t lun = CAM_LUN_WILDCARD;
3117	char *tstr;
3118
3119	if (argc < 3) {
3120		warnx(must, rescan? "rescan" : "reset");
3121		return(1);
3122	}
3123
3124	tstr = argv[optind];
3125	while (isspace(*tstr) && (*tstr != '\0'))
3126		tstr++;
3127	if (strncasecmp(tstr, "all", strlen("all")) == 0)
3128		arglist |= CAM_ARG_BUS;
3129	else if (isdigit(*tstr)) {
3130		rv = parse_btl(argv[optind], &bus, &target, &lun, &arglist);
3131		if (rv != 1 && rv != 3) {
3132			warnx(must, rescan? "rescan" : "reset");
3133			return(1);
3134		}
3135	} else {
3136		char name[30];
3137		int unit;
3138		int fd = -1;
3139		union ccb ccb;
3140
3141		/*
3142		 * Note that resetting or rescanning a device used to
3143		 * require a bus or bus:target:lun.  This is because the
3144		 * device in question may not exist and you're trying to
3145		 * get the controller to rescan to find it.  It may also be
3146		 * because the device is hung / unresponsive, and opening
3147		 * an unresponsive device is not desireable.
3148		 *
3149		 * It can be more convenient to reference a device by
3150		 * peripheral name and unit number, though, and it is
3151		 * possible to get the bus:target:lun for devices that
3152		 * currently exist in the EDT.  So this can work for
3153		 * devices that we want to reset, or devices that exist
3154		 * that we want to rescan, but not devices that do not
3155		 * exist yet.
3156		 *
3157		 * So, we are careful here to look up the bus/target/lun
3158		 * for the device the user wants to operate on, specified
3159		 * by peripheral instance (e.g. da0, pass32) without
3160		 * actually opening that device.  The process is similar to
3161		 * what cam_lookup_pass() does, except that we don't
3162		 * actually open the passthrough driver instance in the end.
3163		 */
3164
3165		if (cam_get_device(tstr, name, sizeof(name), &unit) == -1) {
3166			warnx("%s", cam_errbuf);
3167			error = 1;
3168			goto bailout;
3169		}
3170
3171		if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
3172			warn("Unable to open %s", XPT_DEVICE);
3173			error = 1;
3174			goto bailout;
3175		}
3176
3177		bzero(&ccb, sizeof(ccb));
3178
3179		/*
3180		 * The function code isn't strictly necessary for the
3181		 * GETPASSTHRU ioctl.
3182		 */
3183		ccb.ccb_h.func_code = XPT_GDEVLIST;
3184
3185		/*
3186		 * These two are necessary for the GETPASSTHRU ioctl to
3187		 * work.
3188		 */
3189		strlcpy(ccb.cgdl.periph_name, name,
3190			sizeof(ccb.cgdl.periph_name));
3191		ccb.cgdl.unit_number = unit;
3192
3193		/*
3194		 * Attempt to get the passthrough device.  This ioctl will
3195		 * fail if the device name is null, if the device doesn't
3196		 * exist, or if the passthrough driver isn't in the kernel.
3197		 */
3198		if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) {
3199			warn("Unable to find bus:target:lun for device %s%d",
3200			    name, unit);
3201			error = 1;
3202			close(fd);
3203			goto bailout;
3204		}
3205		if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3206			const struct cam_status_entry *entry;
3207
3208			entry = cam_fetch_status_entry(ccb.ccb_h.status);
3209			warnx("Unable to find bus:target_lun for device %s%d, "
3210			    "CAM status: %s (%#x)", name, unit,
3211			    entry ? entry->status_text : "Unknown",
3212			    ccb.ccb_h.status);
3213			error = 1;
3214			close(fd);
3215			goto bailout;
3216		}
3217
3218		/*
3219		 * The kernel fills in the bus/target/lun.  We don't
3220		 * need the passthrough device name and unit number since
3221		 * we aren't going to open it.
3222		 */
3223		bus = ccb.ccb_h.path_id;
3224		target = ccb.ccb_h.target_id;
3225		lun = ccb.ccb_h.target_lun;
3226
3227		arglist |= CAM_ARG_BUS | CAM_ARG_TARGET | CAM_ARG_LUN;
3228
3229		close(fd);
3230	}
3231
3232	if ((arglist & CAM_ARG_BUS)
3233	    && (arglist & CAM_ARG_TARGET)
3234	    && (arglist & CAM_ARG_LUN))
3235		error = scanlun_or_reset_dev(bus, target, lun, rescan);
3236	else
3237		error = rescan_or_reset_bus(bus, rescan);
3238
3239bailout:
3240
3241	return(error);
3242}
3243
3244static int
3245rescan_or_reset_bus(path_id_t bus, int rescan)
3246{
3247	union ccb *ccb = NULL, *matchccb = NULL;
3248	int fd = -1, retval;
3249	int bufsize;
3250
3251	retval = 0;
3252
3253	if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
3254		warnx("error opening transport layer device %s", XPT_DEVICE);
3255		warn("%s", XPT_DEVICE);
3256		return(1);
3257	}
3258
3259	ccb = malloc(sizeof(*ccb));
3260	if (ccb == NULL) {
3261		warn("failed to allocate CCB");
3262		retval = 1;
3263		goto bailout;
3264	}
3265	bzero(ccb, sizeof(*ccb));
3266
3267	if (bus != CAM_BUS_WILDCARD) {
3268		ccb->ccb_h.func_code = rescan ? XPT_SCAN_BUS : XPT_RESET_BUS;
3269		ccb->ccb_h.path_id = bus;
3270		ccb->ccb_h.target_id = CAM_TARGET_WILDCARD;
3271		ccb->ccb_h.target_lun = CAM_LUN_WILDCARD;
3272		ccb->crcn.flags = CAM_FLAG_NONE;
3273
3274		/* run this at a low priority */
3275		ccb->ccb_h.pinfo.priority = 5;
3276
3277		if (ioctl(fd, CAMIOCOMMAND, ccb) == -1) {
3278			warn("CAMIOCOMMAND ioctl failed");
3279			retval = 1;
3280			goto bailout;
3281		}
3282
3283		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
3284			fprintf(stdout, "%s of bus %d was successful\n",
3285			    rescan ? "Re-scan" : "Reset", bus);
3286		} else {
3287			fprintf(stdout, "%s of bus %d returned error %#x\n",
3288				rescan ? "Re-scan" : "Reset", bus,
3289				ccb->ccb_h.status & CAM_STATUS_MASK);
3290			retval = 1;
3291		}
3292
3293		goto bailout;
3294	}
3295
3296
3297	/*
3298	 * The right way to handle this is to modify the xpt so that it can
3299	 * handle a wildcarded bus in a rescan or reset CCB.  At the moment
3300	 * that isn't implemented, so instead we enumerate the busses and
3301	 * send the rescan or reset to those busses in the case where the
3302	 * given bus is -1 (wildcard).  We don't send a rescan or reset
3303	 * to the xpt bus; sending a rescan to the xpt bus is effectively a
3304	 * no-op, sending a rescan to the xpt bus would result in a status of
3305	 * CAM_REQ_INVALID.
3306	 */
3307	matchccb = malloc(sizeof(*matchccb));
3308	if (matchccb == NULL) {
3309		warn("failed to allocate CCB");
3310		retval = 1;
3311		goto bailout;
3312	}
3313	bzero(matchccb, sizeof(*matchccb));
3314	matchccb->ccb_h.func_code = XPT_DEV_MATCH;
3315	matchccb->ccb_h.path_id = CAM_BUS_WILDCARD;
3316	bufsize = sizeof(struct dev_match_result) * 20;
3317	matchccb->cdm.match_buf_len = bufsize;
3318	matchccb->cdm.matches=(struct dev_match_result *)malloc(bufsize);
3319	if (matchccb->cdm.matches == NULL) {
3320		warnx("can't malloc memory for matches");
3321		retval = 1;
3322		goto bailout;
3323	}
3324	matchccb->cdm.num_matches = 0;
3325
3326	matchccb->cdm.num_patterns = 1;
3327	matchccb->cdm.pattern_buf_len = sizeof(struct dev_match_pattern);
3328
3329	matchccb->cdm.patterns = (struct dev_match_pattern *)malloc(
3330		matchccb->cdm.pattern_buf_len);
3331	if (matchccb->cdm.patterns == NULL) {
3332		warnx("can't malloc memory for patterns");
3333		retval = 1;
3334		goto bailout;
3335	}
3336	matchccb->cdm.patterns[0].type = DEV_MATCH_BUS;
3337	matchccb->cdm.patterns[0].pattern.bus_pattern.flags = BUS_MATCH_ANY;
3338
3339	do {
3340		unsigned int i;
3341
3342		if (ioctl(fd, CAMIOCOMMAND, matchccb) == -1) {
3343			warn("CAMIOCOMMAND ioctl failed");
3344			retval = 1;
3345			goto bailout;
3346		}
3347
3348		if ((matchccb->ccb_h.status != CAM_REQ_CMP)
3349		 || ((matchccb->cdm.status != CAM_DEV_MATCH_LAST)
3350		   && (matchccb->cdm.status != CAM_DEV_MATCH_MORE))) {
3351			warnx("got CAM error %#x, CDM error %d\n",
3352			      matchccb->ccb_h.status, matchccb->cdm.status);
3353			retval = 1;
3354			goto bailout;
3355		}
3356
3357		for (i = 0; i < matchccb->cdm.num_matches; i++) {
3358			struct bus_match_result *bus_result;
3359
3360			/* This shouldn't happen. */
3361			if (matchccb->cdm.matches[i].type != DEV_MATCH_BUS)
3362				continue;
3363
3364			bus_result =&matchccb->cdm.matches[i].result.bus_result;
3365
3366			/*
3367			 * We don't want to rescan or reset the xpt bus.
3368			 * See above.
3369			 */
3370			if (bus_result->path_id == CAM_XPT_PATH_ID)
3371				continue;
3372
3373			ccb->ccb_h.func_code = rescan ? XPT_SCAN_BUS :
3374						       XPT_RESET_BUS;
3375			ccb->ccb_h.path_id = bus_result->path_id;
3376			ccb->ccb_h.target_id = CAM_TARGET_WILDCARD;
3377			ccb->ccb_h.target_lun = CAM_LUN_WILDCARD;
3378			ccb->crcn.flags = CAM_FLAG_NONE;
3379
3380			/* run this at a low priority */
3381			ccb->ccb_h.pinfo.priority = 5;
3382
3383			if (ioctl(fd, CAMIOCOMMAND, ccb) == -1) {
3384				warn("CAMIOCOMMAND ioctl failed");
3385				retval = 1;
3386				goto bailout;
3387			}
3388
3389			if ((ccb->ccb_h.status & CAM_STATUS_MASK)==CAM_REQ_CMP){
3390				fprintf(stdout, "%s of bus %d was successful\n",
3391					rescan? "Re-scan" : "Reset",
3392					bus_result->path_id);
3393			} else {
3394				/*
3395				 * Don't bail out just yet, maybe the other
3396				 * rescan or reset commands will complete
3397				 * successfully.
3398				 */
3399				fprintf(stderr, "%s of bus %d returned error "
3400					"%#x\n", rescan? "Re-scan" : "Reset",
3401					bus_result->path_id,
3402					ccb->ccb_h.status & CAM_STATUS_MASK);
3403				retval = 1;
3404			}
3405		}
3406	} while ((matchccb->ccb_h.status == CAM_REQ_CMP)
3407		 && (matchccb->cdm.status == CAM_DEV_MATCH_MORE));
3408
3409bailout:
3410
3411	if (fd != -1)
3412		close(fd);
3413
3414	if (matchccb != NULL) {
3415		free(matchccb->cdm.patterns);
3416		free(matchccb->cdm.matches);
3417		free(matchccb);
3418	}
3419	free(ccb);
3420
3421	return(retval);
3422}
3423
3424static int
3425scanlun_or_reset_dev(path_id_t bus, target_id_t target, lun_id_t lun, int scan)
3426{
3427	union ccb ccb;
3428	struct cam_device *device;
3429	int fd;
3430
3431	device = NULL;
3432
3433	if (bus == CAM_BUS_WILDCARD) {
3434		warnx("invalid bus number %d", bus);
3435		return(1);
3436	}
3437
3438	if (target == CAM_TARGET_WILDCARD) {
3439		warnx("invalid target number %d", target);
3440		return(1);
3441	}
3442
3443	if (lun == CAM_LUN_WILDCARD) {
3444		warnx("invalid lun number %jx", (uintmax_t)lun);
3445		return(1);
3446	}
3447
3448	fd = -1;
3449
3450	bzero(&ccb, sizeof(union ccb));
3451
3452	if (scan) {
3453		if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
3454			warnx("error opening transport layer device %s\n",
3455			    XPT_DEVICE);
3456			warn("%s", XPT_DEVICE);
3457			return(1);
3458		}
3459	} else {
3460		device = cam_open_btl(bus, target, lun, O_RDWR, NULL);
3461		if (device == NULL) {
3462			warnx("%s", cam_errbuf);
3463			return(1);
3464		}
3465	}
3466
3467	ccb.ccb_h.func_code = (scan)? XPT_SCAN_LUN : XPT_RESET_DEV;
3468	ccb.ccb_h.path_id = bus;
3469	ccb.ccb_h.target_id = target;
3470	ccb.ccb_h.target_lun = lun;
3471	ccb.ccb_h.timeout = 5000;
3472	ccb.crcn.flags = CAM_FLAG_NONE;
3473
3474	/* run this at a low priority */
3475	ccb.ccb_h.pinfo.priority = 5;
3476
3477	if (scan) {
3478		if (ioctl(fd, CAMIOCOMMAND, &ccb) < 0) {
3479			warn("CAMIOCOMMAND ioctl failed");
3480			close(fd);
3481			return(1);
3482		}
3483	} else {
3484		if (cam_send_ccb(device, &ccb) < 0) {
3485			warn("error sending XPT_RESET_DEV CCB");
3486			cam_close_device(device);
3487			return(1);
3488		}
3489	}
3490
3491	if (scan)
3492		close(fd);
3493	else
3494		cam_close_device(device);
3495
3496	/*
3497	 * An error code of CAM_BDR_SENT is normal for a BDR request.
3498	 */
3499	if (((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
3500	 || ((!scan)
3501	  && ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_BDR_SENT))) {
3502		fprintf(stdout, "%s of %d:%d:%jx was successful\n",
3503		    scan? "Re-scan" : "Reset", bus, target, (uintmax_t)lun);
3504		return(0);
3505	} else {
3506		fprintf(stdout, "%s of %d:%d:%jx returned error %#x\n",
3507		    scan? "Re-scan" : "Reset", bus, target, (uintmax_t)lun,
3508		    ccb.ccb_h.status & CAM_STATUS_MASK);
3509		return(1);
3510	}
3511}
3512
3513#ifndef MINIMALISTIC
3514
3515static struct scsi_nv defect_list_type_map[] = {
3516	{ "block", SRDD10_BLOCK_FORMAT },
3517	{ "extbfi", SRDD10_EXT_BFI_FORMAT },
3518	{ "extphys", SRDD10_EXT_PHYS_FORMAT },
3519	{ "longblock", SRDD10_LONG_BLOCK_FORMAT },
3520	{ "bfi", SRDD10_BYTES_FROM_INDEX_FORMAT },
3521	{ "phys", SRDD10_PHYSICAL_SECTOR_FORMAT }
3522};
3523
3524static int
3525readdefects(struct cam_device *device, int argc, char **argv,
3526	    char *combinedopt, int task_attr, int retry_count, int timeout)
3527{
3528	union ccb *ccb = NULL;
3529	struct scsi_read_defect_data_hdr_10 *hdr10 = NULL;
3530	struct scsi_read_defect_data_hdr_12 *hdr12 = NULL;
3531	size_t hdr_size = 0, entry_size = 0;
3532	int use_12byte = 0;
3533	int hex_format = 0;
3534	u_int8_t *defect_list = NULL;
3535	u_int8_t list_format = 0;
3536	int list_type_set = 0;
3537	u_int32_t dlist_length = 0;
3538	u_int32_t returned_length = 0, valid_len = 0;
3539	u_int32_t num_returned = 0, num_valid = 0;
3540	u_int32_t max_possible_size = 0, hdr_max = 0;
3541	u_int32_t starting_offset = 0;
3542	u_int8_t returned_format, returned_type;
3543	unsigned int i;
3544	int summary = 0, quiet = 0;
3545	int c, error = 0;
3546	int lists_specified = 0;
3547	int get_length = 1, first_pass = 1;
3548	int mads = 0;
3549
3550	while ((c = getopt(argc, argv, combinedopt)) != -1) {
3551		switch(c){
3552		case 'f':
3553		{
3554			scsi_nv_status status;
3555			int entry_num = 0;
3556
3557			status = scsi_get_nv(defect_list_type_map,
3558			    sizeof(defect_list_type_map) /
3559			    sizeof(defect_list_type_map[0]), optarg,
3560			    &entry_num, SCSI_NV_FLAG_IG_CASE);
3561
3562			if (status == SCSI_NV_FOUND) {
3563				list_format = defect_list_type_map[
3564				    entry_num].value;
3565				list_type_set = 1;
3566			} else {
3567				warnx("%s: %s %s option %s", __func__,
3568				    (status == SCSI_NV_AMBIGUOUS) ?
3569				    "ambiguous" : "invalid", "defect list type",
3570				    optarg);
3571				error = 1;
3572				goto defect_bailout;
3573			}
3574			break;
3575		}
3576		case 'G':
3577			arglist |= CAM_ARG_GLIST;
3578			break;
3579		case 'P':
3580			arglist |= CAM_ARG_PLIST;
3581			break;
3582		case 'q':
3583			quiet = 1;
3584			break;
3585		case 's':
3586			summary = 1;
3587			break;
3588		case 'S': {
3589			char *endptr;
3590
3591			starting_offset = strtoul(optarg, &endptr, 0);
3592			if (*endptr != '\0') {
3593				error = 1;
3594				warnx("invalid starting offset %s", optarg);
3595				goto defect_bailout;
3596			}
3597			break;
3598		}
3599		case 'X':
3600			hex_format = 1;
3601			break;
3602		default:
3603			break;
3604		}
3605	}
3606
3607	if (list_type_set == 0) {
3608		error = 1;
3609		warnx("no defect list format specified");
3610		goto defect_bailout;
3611	}
3612
3613	if (arglist & CAM_ARG_PLIST) {
3614		list_format |= SRDD10_PLIST;
3615		lists_specified++;
3616	}
3617
3618	if (arglist & CAM_ARG_GLIST) {
3619		list_format |= SRDD10_GLIST;
3620		lists_specified++;
3621	}
3622
3623	/*
3624	 * This implies a summary, and was the previous behavior.
3625	 */
3626	if (lists_specified == 0)
3627		summary = 1;
3628
3629	ccb = cam_getccb(device);
3630
3631retry_12byte:
3632
3633	/*
3634	 * We start off asking for just the header to determine how much
3635	 * defect data is available.  Some Hitachi drives return an error
3636	 * if you ask for more data than the drive has.  Once we know the
3637	 * length, we retry the command with the returned length.
3638	 */
3639	if (use_12byte == 0)
3640		dlist_length = sizeof(*hdr10);
3641	else
3642		dlist_length = sizeof(*hdr12);
3643
3644retry:
3645	if (defect_list != NULL) {
3646		free(defect_list);
3647		defect_list = NULL;
3648	}
3649	defect_list = malloc(dlist_length);
3650	if (defect_list == NULL) {
3651		warnx("can't malloc memory for defect list");
3652		error = 1;
3653		goto defect_bailout;
3654	}
3655
3656next_batch:
3657	bzero(defect_list, dlist_length);
3658
3659	/*
3660	 * cam_getccb() zeros the CCB header only.  So we need to zero the
3661	 * payload portion of the ccb.
3662	 */
3663	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
3664
3665	scsi_read_defects(&ccb->csio,
3666			  /*retries*/ retry_count,
3667			  /*cbfcnp*/ NULL,
3668			  /*tag_action*/ task_attr,
3669			  /*list_format*/ list_format,
3670			  /*addr_desc_index*/ starting_offset,
3671			  /*data_ptr*/ defect_list,
3672			  /*dxfer_len*/ dlist_length,
3673			  /*minimum_cmd_size*/ use_12byte ? 12 : 0,
3674			  /*sense_len*/ SSD_FULL_SIZE,
3675			  /*timeout*/ timeout ? timeout : 5000);
3676
3677	/* Disable freezing the device queue */
3678	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
3679
3680	if (cam_send_ccb(device, ccb) < 0) {
3681		perror("error reading defect list");
3682
3683		if (arglist & CAM_ARG_VERBOSE) {
3684			cam_error_print(device, ccb, CAM_ESF_ALL,
3685					CAM_EPF_ALL, stderr);
3686		}
3687
3688		error = 1;
3689		goto defect_bailout;
3690	}
3691
3692	valid_len = ccb->csio.dxfer_len - ccb->csio.resid;
3693
3694	if (use_12byte == 0) {
3695		hdr10 = (struct scsi_read_defect_data_hdr_10 *)defect_list;
3696		hdr_size = sizeof(*hdr10);
3697		hdr_max = SRDDH10_MAX_LENGTH;
3698
3699		if (valid_len >= hdr_size) {
3700			returned_length = scsi_2btoul(hdr10->length);
3701			returned_format = hdr10->format;
3702		} else {
3703			returned_length = 0;
3704			returned_format = 0;
3705		}
3706	} else {
3707		hdr12 = (struct scsi_read_defect_data_hdr_12 *)defect_list;
3708		hdr_size = sizeof(*hdr12);
3709		hdr_max = SRDDH12_MAX_LENGTH;
3710
3711		if (valid_len >= hdr_size) {
3712			returned_length = scsi_4btoul(hdr12->length);
3713			returned_format = hdr12->format;
3714		} else {
3715			returned_length = 0;
3716			returned_format = 0;
3717		}
3718	}
3719
3720	returned_type = returned_format & SRDDH10_DLIST_FORMAT_MASK;
3721	switch (returned_type) {
3722	case SRDD10_BLOCK_FORMAT:
3723		entry_size = sizeof(struct scsi_defect_desc_block);
3724		break;
3725	case SRDD10_LONG_BLOCK_FORMAT:
3726		entry_size = sizeof(struct scsi_defect_desc_long_block);
3727		break;
3728	case SRDD10_EXT_PHYS_FORMAT:
3729	case SRDD10_PHYSICAL_SECTOR_FORMAT:
3730		entry_size = sizeof(struct scsi_defect_desc_phys_sector);
3731		break;
3732	case SRDD10_EXT_BFI_FORMAT:
3733	case SRDD10_BYTES_FROM_INDEX_FORMAT:
3734		entry_size = sizeof(struct scsi_defect_desc_bytes_from_index);
3735		break;
3736	default:
3737		warnx("Unknown defect format 0x%x\n", returned_type);
3738		error = 1;
3739		goto defect_bailout;
3740		break;
3741	}
3742
3743	max_possible_size = (hdr_max / entry_size) * entry_size;
3744	num_returned = returned_length / entry_size;
3745	num_valid = min(returned_length, valid_len - hdr_size);
3746	num_valid /= entry_size;
3747
3748	if (get_length != 0) {
3749		get_length = 0;
3750
3751		if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
3752		     CAM_SCSI_STATUS_ERROR) {
3753			struct scsi_sense_data *sense;
3754			int error_code, sense_key, asc, ascq;
3755
3756			sense = &ccb->csio.sense_data;
3757			scsi_extract_sense_len(sense, ccb->csio.sense_len -
3758			    ccb->csio.sense_resid, &error_code, &sense_key,
3759			    &asc, &ascq, /*show_errors*/ 1);
3760
3761			/*
3762			 * If the drive is reporting that it just doesn't
3763			 * support the defect list format, go ahead and use
3764			 * the length it reported.  Otherwise, the length
3765			 * may not be valid, so use the maximum.
3766			 */
3767			if ((sense_key == SSD_KEY_RECOVERED_ERROR)
3768			 && (asc == 0x1c) && (ascq == 0x00)
3769			 && (returned_length > 0)) {
3770				if ((use_12byte == 0)
3771				 && (returned_length >= max_possible_size)) {
3772					get_length = 1;
3773					use_12byte = 1;
3774					goto retry_12byte;
3775				}
3776				dlist_length = returned_length + hdr_size;
3777			} else if ((sense_key == SSD_KEY_RECOVERED_ERROR)
3778				&& (asc == 0x1f) && (ascq == 0x00)
3779				&& (returned_length > 0)) {
3780				/* Partial defect list transfer */
3781				/*
3782				 * Hitachi drives return this error
3783				 * along with a partial defect list if they
3784				 * have more defects than the 10 byte
3785				 * command can support.  Retry with the 12
3786				 * byte command.
3787				 */
3788				if (use_12byte == 0) {
3789					get_length = 1;
3790					use_12byte = 1;
3791					goto retry_12byte;
3792				}
3793				dlist_length = returned_length + hdr_size;
3794			} else if ((sense_key == SSD_KEY_ILLEGAL_REQUEST)
3795				&& (asc == 0x24) && (ascq == 0x00)) {
3796				/* Invalid field in CDB */
3797				/*
3798				 * SBC-3 says that if the drive has more
3799				 * defects than can be reported with the
3800				 * 10 byte command, it should return this
3801	 			 * error and no data.  Retry with the 12
3802				 * byte command.
3803				 */
3804				if (use_12byte == 0) {
3805					get_length = 1;
3806					use_12byte = 1;
3807					goto retry_12byte;
3808				}
3809				dlist_length = returned_length + hdr_size;
3810			} else {
3811				/*
3812				 * If we got a SCSI error and no valid length,
3813				 * just use the 10 byte maximum.  The 12
3814				 * byte maximum is too large.
3815				 */
3816				if (returned_length == 0)
3817					dlist_length = SRDD10_MAX_LENGTH;
3818				else {
3819					if ((use_12byte == 0)
3820					 && (returned_length >=
3821					     max_possible_size)) {
3822						get_length = 1;
3823						use_12byte = 1;
3824						goto retry_12byte;
3825					}
3826					dlist_length = returned_length +
3827					    hdr_size;
3828				}
3829			}
3830		} else if ((ccb->ccb_h.status & CAM_STATUS_MASK) !=
3831			    CAM_REQ_CMP){
3832			error = 1;
3833			warnx("Error reading defect header");
3834			if (arglist & CAM_ARG_VERBOSE)
3835				cam_error_print(device, ccb, CAM_ESF_ALL,
3836						CAM_EPF_ALL, stderr);
3837			goto defect_bailout;
3838		} else {
3839			if ((use_12byte == 0)
3840			 && (returned_length >= max_possible_size)) {
3841				get_length = 1;
3842				use_12byte = 1;
3843				goto retry_12byte;
3844			}
3845			dlist_length = returned_length + hdr_size;
3846		}
3847		if (summary != 0) {
3848			fprintf(stdout, "%u", num_returned);
3849			if (quiet == 0) {
3850				fprintf(stdout, " defect%s",
3851					(num_returned != 1) ? "s" : "");
3852			}
3853			fprintf(stdout, "\n");
3854
3855			goto defect_bailout;
3856		}
3857
3858		/*
3859		 * We always limit the list length to the 10-byte maximum
3860		 * length (0xffff).  The reason is that some controllers
3861		 * can't handle larger I/Os, and we can transfer the entire
3862		 * 10 byte list in one shot.  For drives that support the 12
3863		 * byte read defects command, we'll step through the list
3864		 * by specifying a starting offset.  For drives that don't
3865		 * support the 12 byte command's starting offset, we'll
3866		 * just display the first 64K.
3867		 */
3868		dlist_length = min(dlist_length, SRDD10_MAX_LENGTH);
3869
3870		goto retry;
3871	}
3872
3873
3874	if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR)
3875	 && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
3876	 && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) {
3877		struct scsi_sense_data *sense;
3878		int error_code, sense_key, asc, ascq;
3879
3880		sense = &ccb->csio.sense_data;
3881		scsi_extract_sense_len(sense, ccb->csio.sense_len -
3882		    ccb->csio.sense_resid, &error_code, &sense_key, &asc,
3883		    &ascq, /*show_errors*/ 1);
3884
3885		/*
3886		 * According to the SCSI spec, if the disk doesn't support
3887		 * the requested format, it will generally return a sense
3888		 * key of RECOVERED ERROR, and an additional sense code
3889		 * of "DEFECT LIST NOT FOUND".  HGST drives also return
3890		 * Primary/Grown defect list not found errors.  So just
3891		 * check for an ASC of 0x1c.
3892		 */
3893		if ((sense_key == SSD_KEY_RECOVERED_ERROR)
3894		 && (asc == 0x1c)) {
3895			const char *format_str;
3896
3897			format_str = scsi_nv_to_str(defect_list_type_map,
3898			    sizeof(defect_list_type_map) /
3899			    sizeof(defect_list_type_map[0]),
3900			    list_format & SRDD10_DLIST_FORMAT_MASK);
3901			warnx("requested defect format %s not available",
3902			    format_str ? format_str : "unknown");
3903
3904			format_str = scsi_nv_to_str(defect_list_type_map,
3905			    sizeof(defect_list_type_map) /
3906			    sizeof(defect_list_type_map[0]), returned_type);
3907			if (format_str != NULL) {
3908				warnx("Device returned %s format",
3909				    format_str);
3910			} else {
3911				error = 1;
3912				warnx("Device returned unknown defect"
3913				     " data format %#x", returned_type);
3914				goto defect_bailout;
3915			}
3916		} else {
3917			error = 1;
3918			warnx("Error returned from read defect data command");
3919			if (arglist & CAM_ARG_VERBOSE)
3920				cam_error_print(device, ccb, CAM_ESF_ALL,
3921						CAM_EPF_ALL, stderr);
3922			goto defect_bailout;
3923		}
3924	} else if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3925		error = 1;
3926		warnx("Error returned from read defect data command");
3927		if (arglist & CAM_ARG_VERBOSE)
3928			cam_error_print(device, ccb, CAM_ESF_ALL,
3929					CAM_EPF_ALL, stderr);
3930		goto defect_bailout;
3931	}
3932
3933	if (first_pass != 0) {
3934		fprintf(stderr, "Got %d defect", num_returned);
3935
3936		if ((lists_specified == 0) || (num_returned == 0)) {
3937			fprintf(stderr, "s.\n");
3938			goto defect_bailout;
3939		} else if (num_returned == 1)
3940			fprintf(stderr, ":\n");
3941		else
3942			fprintf(stderr, "s:\n");
3943
3944		first_pass = 0;
3945	}
3946
3947	/*
3948	 * XXX KDM  I should probably clean up the printout format for the
3949	 * disk defects.
3950	 */
3951	switch (returned_type) {
3952	case SRDD10_PHYSICAL_SECTOR_FORMAT:
3953	case SRDD10_EXT_PHYS_FORMAT:
3954	{
3955		struct scsi_defect_desc_phys_sector *dlist;
3956
3957		dlist = (struct scsi_defect_desc_phys_sector *)
3958			(defect_list + hdr_size);
3959
3960		for (i = 0; i < num_valid; i++) {
3961			uint32_t sector;
3962
3963			sector = scsi_4btoul(dlist[i].sector);
3964			if (returned_type == SRDD10_EXT_PHYS_FORMAT) {
3965				mads = (sector & SDD_EXT_PHYS_MADS) ?
3966				       0 : 1;
3967				sector &= ~SDD_EXT_PHYS_FLAG_MASK;
3968			}
3969			if (hex_format == 0)
3970				fprintf(stdout, "%d:%d:%d%s",
3971					scsi_3btoul(dlist[i].cylinder),
3972					dlist[i].head,
3973					scsi_4btoul(dlist[i].sector),
3974					mads ? " - " : "\n");
3975			else
3976				fprintf(stdout, "0x%x:0x%x:0x%x%s",
3977					scsi_3btoul(dlist[i].cylinder),
3978					dlist[i].head,
3979					scsi_4btoul(dlist[i].sector),
3980					mads ? " - " : "\n");
3981			mads = 0;
3982		}
3983		if (num_valid < num_returned) {
3984			starting_offset += num_valid;
3985			goto next_batch;
3986		}
3987		break;
3988	}
3989	case SRDD10_BYTES_FROM_INDEX_FORMAT:
3990	case SRDD10_EXT_BFI_FORMAT:
3991	{
3992		struct scsi_defect_desc_bytes_from_index *dlist;
3993
3994		dlist = (struct scsi_defect_desc_bytes_from_index *)
3995			(defect_list + hdr_size);
3996
3997		for (i = 0; i < num_valid; i++) {
3998			uint32_t bfi;
3999
4000			bfi = scsi_4btoul(dlist[i].bytes_from_index);
4001			if (returned_type == SRDD10_EXT_BFI_FORMAT) {
4002				mads = (bfi & SDD_EXT_BFI_MADS) ? 1 : 0;
4003				bfi &= ~SDD_EXT_BFI_FLAG_MASK;
4004			}
4005			if (hex_format == 0)
4006				fprintf(stdout, "%d:%d:%d%s",
4007					scsi_3btoul(dlist[i].cylinder),
4008					dlist[i].head,
4009					scsi_4btoul(dlist[i].bytes_from_index),
4010					mads ? " - " : "\n");
4011			else
4012				fprintf(stdout, "0x%x:0x%x:0x%x%s",
4013					scsi_3btoul(dlist[i].cylinder),
4014					dlist[i].head,
4015					scsi_4btoul(dlist[i].bytes_from_index),
4016					mads ? " - " : "\n");
4017
4018			mads = 0;
4019		}
4020		if (num_valid < num_returned) {
4021			starting_offset += num_valid;
4022			goto next_batch;
4023		}
4024		break;
4025	}
4026	case SRDDH10_BLOCK_FORMAT:
4027	{
4028		struct scsi_defect_desc_block *dlist;
4029
4030		dlist = (struct scsi_defect_desc_block *)
4031			(defect_list + hdr_size);
4032
4033		for (i = 0; i < num_valid; i++) {
4034			if (hex_format == 0)
4035				fprintf(stdout, "%u\n",
4036					scsi_4btoul(dlist[i].address));
4037			else
4038				fprintf(stdout, "0x%x\n",
4039					scsi_4btoul(dlist[i].address));
4040		}
4041
4042		if (num_valid < num_returned) {
4043			starting_offset += num_valid;
4044			goto next_batch;
4045		}
4046
4047		break;
4048	}
4049	case SRDD10_LONG_BLOCK_FORMAT:
4050	{
4051		struct scsi_defect_desc_long_block *dlist;
4052
4053		dlist = (struct scsi_defect_desc_long_block *)
4054			(defect_list + hdr_size);
4055
4056		for (i = 0; i < num_valid; i++) {
4057			if (hex_format == 0)
4058				fprintf(stdout, "%ju\n",
4059					(uintmax_t)scsi_8btou64(
4060					dlist[i].address));
4061			else
4062				fprintf(stdout, "0x%jx\n",
4063					(uintmax_t)scsi_8btou64(
4064					dlist[i].address));
4065		}
4066
4067		if (num_valid < num_returned) {
4068			starting_offset += num_valid;
4069			goto next_batch;
4070		}
4071		break;
4072	}
4073	default:
4074		fprintf(stderr, "Unknown defect format 0x%x\n",
4075			returned_type);
4076		error = 1;
4077		break;
4078	}
4079defect_bailout:
4080
4081	if (defect_list != NULL)
4082		free(defect_list);
4083
4084	if (ccb != NULL)
4085		cam_freeccb(ccb);
4086
4087	return(error);
4088}
4089#endif /* MINIMALISTIC */
4090
4091#if 0
4092void
4093reassignblocks(struct cam_device *device, u_int32_t *blocks, int num_blocks)
4094{
4095	union ccb *ccb;
4096
4097	ccb = cam_getccb(device);
4098
4099	cam_freeccb(ccb);
4100}
4101#endif
4102
4103#ifndef MINIMALISTIC
4104void
4105mode_sense(struct cam_device *device, int dbd, int pc, int page, int subpage,
4106	   int task_attr, int retry_count, int timeout, u_int8_t *data,
4107	   int datalen)
4108{
4109	union ccb *ccb;
4110	int retval;
4111
4112	ccb = cam_getccb(device);
4113
4114	if (ccb == NULL)
4115		errx(1, "mode_sense: couldn't allocate CCB");
4116
4117	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
4118
4119	scsi_mode_sense_subpage(&ccb->csio,
4120			/* retries */ retry_count,
4121			/* cbfcnp */ NULL,
4122			/* tag_action */ task_attr,
4123			/* dbd */ dbd,
4124			/* pc */ pc << 6,
4125			/* page */ page,
4126			/* subpage */ subpage,
4127			/* param_buf */ data,
4128			/* param_len */ datalen,
4129			/* minimum_cmd_size */ 0,
4130			/* sense_len */ SSD_FULL_SIZE,
4131			/* timeout */ timeout ? timeout : 5000);
4132
4133	if (arglist & CAM_ARG_ERR_RECOVER)
4134		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
4135
4136	/* Disable freezing the device queue */
4137	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
4138
4139	if (((retval = cam_send_ccb(device, ccb)) < 0)
4140	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
4141		if (arglist & CAM_ARG_VERBOSE) {
4142			cam_error_print(device, ccb, CAM_ESF_ALL,
4143					CAM_EPF_ALL, stderr);
4144		}
4145		cam_freeccb(ccb);
4146		cam_close_device(device);
4147		if (retval < 0)
4148			err(1, "error sending mode sense command");
4149		else
4150			errx(1, "error sending mode sense command");
4151	}
4152
4153	cam_freeccb(ccb);
4154}
4155
4156void
4157mode_select(struct cam_device *device, int save_pages, int task_attr,
4158	    int retry_count, int timeout, u_int8_t *data, int datalen)
4159{
4160	union ccb *ccb;
4161	int retval;
4162
4163	ccb = cam_getccb(device);
4164
4165	if (ccb == NULL)
4166		errx(1, "mode_select: couldn't allocate CCB");
4167
4168	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
4169
4170	scsi_mode_select(&ccb->csio,
4171			 /* retries */ retry_count,
4172			 /* cbfcnp */ NULL,
4173			 /* tag_action */ task_attr,
4174			 /* scsi_page_fmt */ 1,
4175			 /* save_pages */ save_pages,
4176			 /* param_buf */ data,
4177			 /* param_len */ datalen,
4178			 /* sense_len */ SSD_FULL_SIZE,
4179			 /* timeout */ timeout ? timeout : 5000);
4180
4181	if (arglist & CAM_ARG_ERR_RECOVER)
4182		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
4183
4184	/* Disable freezing the device queue */
4185	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
4186
4187	if (((retval = cam_send_ccb(device, ccb)) < 0)
4188	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
4189		if (arglist & CAM_ARG_VERBOSE) {
4190			cam_error_print(device, ccb, CAM_ESF_ALL,
4191					CAM_EPF_ALL, stderr);
4192		}
4193		cam_freeccb(ccb);
4194		cam_close_device(device);
4195
4196		if (retval < 0)
4197			err(1, "error sending mode select command");
4198		else
4199			errx(1, "error sending mode select command");
4200
4201	}
4202
4203	cam_freeccb(ccb);
4204}
4205
4206void
4207modepage(struct cam_device *device, int argc, char **argv, char *combinedopt,
4208	 int task_attr, int retry_count, int timeout)
4209{
4210	char *str_subpage;
4211	int c, page = -1, subpage = -1, pc = 0;
4212	int binary = 0, dbd = 0, edit = 0, list = 0;
4213
4214	while ((c = getopt(argc, argv, combinedopt)) != -1) {
4215		switch(c) {
4216		case 'b':
4217			binary = 1;
4218			break;
4219		case 'd':
4220			dbd = 1;
4221			break;
4222		case 'e':
4223			edit = 1;
4224			break;
4225		case 'l':
4226			list++;
4227			break;
4228		case 'm':
4229			str_subpage = optarg;
4230			strsep(&str_subpage, ",");
4231			page = strtol(optarg, NULL, 0);
4232			if (str_subpage)
4233			    subpage = strtol(str_subpage, NULL, 0);
4234			else
4235			    subpage = 0;
4236			if (page < 0)
4237				errx(1, "invalid mode page %d", page);
4238			if (subpage < 0)
4239				errx(1, "invalid mode subpage %d", subpage);
4240			break;
4241		case 'P':
4242			pc = strtol(optarg, NULL, 0);
4243			if ((pc < 0) || (pc > 3))
4244				errx(1, "invalid page control field %d", pc);
4245			break;
4246		default:
4247			break;
4248		}
4249	}
4250
4251	if (page == -1 && list == 0)
4252		errx(1, "you must specify a mode page!");
4253
4254	if (list != 0) {
4255		mode_list(device, dbd, pc, list > 1, task_attr, retry_count,
4256			  timeout);
4257	} else {
4258		mode_edit(device, dbd, pc, page, subpage, edit, binary,
4259		    task_attr, retry_count, timeout);
4260	}
4261}
4262
4263static int
4264scsicmd(struct cam_device *device, int argc, char **argv, char *combinedopt,
4265	int task_attr, int retry_count, int timeout)
4266{
4267	union ccb *ccb;
4268	u_int32_t flags = CAM_DIR_NONE;
4269	u_int8_t *data_ptr = NULL;
4270	u_int8_t cdb[20];
4271	u_int8_t atacmd[12];
4272	struct get_hook hook;
4273	int c, data_bytes = 0, valid_bytes;
4274	int cdb_len = 0;
4275	int atacmd_len = 0;
4276	int dmacmd = 0;
4277	int fpdmacmd = 0;
4278	int need_res = 0;
4279	char *datastr = NULL, *tstr, *resstr = NULL;
4280	int error = 0;
4281	int fd_data = 0, fd_res = 0;
4282	int retval;
4283
4284	ccb = cam_getccb(device);
4285
4286	if (ccb == NULL) {
4287		warnx("scsicmd: error allocating ccb");
4288		return(1);
4289	}
4290
4291	CCB_CLEAR_ALL_EXCEPT_HDR(ccb);
4292
4293	while ((c = getopt(argc, argv, combinedopt)) != -1) {
4294		switch(c) {
4295		case 'a':
4296			tstr = optarg;
4297			while (isspace(*tstr) && (*tstr != '\0'))
4298				tstr++;
4299			hook.argc = argc - optind;
4300			hook.argv = argv + optind;
4301			hook.got = 0;
4302			atacmd_len = buff_encode_visit(atacmd, sizeof(atacmd), tstr,
4303						    iget, &hook);
4304			/*
4305			 * Increment optind by the number of arguments the
4306			 * encoding routine processed.  After each call to
4307			 * getopt(3), optind points to the argument that
4308			 * getopt should process _next_.  In this case,
4309			 * that means it points to the first command string
4310			 * argument, if there is one.  Once we increment
4311			 * this, it should point to either the next command
4312			 * line argument, or it should be past the end of
4313			 * the list.
4314			 */
4315			optind += hook.got;
4316			break;
4317		case 'c':
4318			tstr = optarg;
4319			while (isspace(*tstr) && (*tstr != '\0'))
4320				tstr++;
4321			hook.argc = argc - optind;
4322			hook.argv = argv + optind;
4323			hook.got = 0;
4324			cdb_len = buff_encode_visit(cdb, sizeof(cdb), tstr,
4325						    iget, &hook);
4326			/*
4327			 * Increment optind by the number of arguments the
4328			 * encoding routine processed.  After each call to
4329			 * getopt(3), optind points to the argument that
4330			 * getopt should process _next_.  In this case,
4331			 * that means it points to the first command string
4332			 * argument, if there is one.  Once we increment
4333			 * this, it should point to either the next command
4334			 * line argument, or it should be past the end of
4335			 * the list.
4336			 */
4337			optind += hook.got;
4338			break;
4339		case 'd':
4340			dmacmd = 1;
4341			break;
4342		case 'f':
4343			fpdmacmd = 1;
4344			break;
4345		case 'i':
4346			if (arglist & CAM_ARG_CMD_OUT) {
4347				warnx("command must either be "
4348				      "read or write, not both");
4349				error = 1;
4350				goto scsicmd_bailout;
4351			}
4352			arglist |= CAM_ARG_CMD_IN;
4353			flags = CAM_DIR_IN;
4354			data_bytes = strtol(optarg, NULL, 0);
4355			if (data_bytes <= 0) {
4356				warnx("invalid number of input bytes %d",
4357				      data_bytes);
4358				error = 1;
4359				goto scsicmd_bailout;
4360			}
4361			hook.argc = argc - optind;
4362			hook.argv = argv + optind;
4363			hook.got = 0;
4364			optind++;
4365			datastr = cget(&hook, NULL);
4366			/*
4367			 * If the user supplied "-" instead of a format, he
4368			 * wants the data to be written to stdout.
4369			 */
4370			if ((datastr != NULL)
4371			 && (datastr[0] == '-'))
4372				fd_data = 1;
4373
4374			data_ptr = (u_int8_t *)malloc(data_bytes);
4375			if (data_ptr == NULL) {
4376				warnx("can't malloc memory for data_ptr");
4377				error = 1;
4378				goto scsicmd_bailout;
4379			}
4380			break;
4381		case 'o':
4382			if (arglist & CAM_ARG_CMD_IN) {
4383				warnx("command must either be "
4384				      "read or write, not both");
4385				error = 1;
4386				goto scsicmd_bailout;
4387			}
4388			arglist |= CAM_ARG_CMD_OUT;
4389			flags = CAM_DIR_OUT;
4390			data_bytes = strtol(optarg, NULL, 0);
4391			if (data_bytes <= 0) {
4392				warnx("invalid number of output bytes %d",
4393				      data_bytes);
4394				error = 1;
4395				goto scsicmd_bailout;
4396			}
4397			hook.argc = argc - optind;
4398			hook.argv = argv + optind;
4399			hook.got = 0;
4400			datastr = cget(&hook, NULL);
4401			data_ptr = (u_int8_t *)malloc(data_bytes);
4402			if (data_ptr == NULL) {
4403				warnx("can't malloc memory for data_ptr");
4404				error = 1;
4405				goto scsicmd_bailout;
4406			}
4407			bzero(data_ptr, data_bytes);
4408			/*
4409			 * If the user supplied "-" instead of a format, he
4410			 * wants the data to be read from stdin.
4411			 */
4412			if ((datastr != NULL)
4413			 && (datastr[0] == '-'))
4414				fd_data = 1;
4415			else
4416				buff_encode_visit(data_ptr, data_bytes, datastr,
4417						  iget, &hook);
4418			optind += hook.got;
4419			break;
4420		case 'r':
4421			need_res = 1;
4422			hook.argc = argc - optind;
4423			hook.argv = argv + optind;
4424			hook.got = 0;
4425			resstr = cget(&hook, NULL);
4426			if ((resstr != NULL) && (resstr[0] == '-'))
4427				fd_res = 1;
4428			optind += hook.got;
4429			break;
4430		default:
4431			break;
4432		}
4433	}
4434
4435	/*
4436	 * If fd_data is set, and we're writing to the device, we need to
4437	 * read the data the user wants written from stdin.
4438	 */
4439	if ((fd_data == 1) && (arglist & CAM_ARG_CMD_OUT)) {
4440		ssize_t amt_read;
4441		int amt_to_read = data_bytes;
4442		u_int8_t *buf_ptr = data_ptr;
4443
4444		for (amt_read = 0; amt_to_read > 0;
4445		     amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) {
4446			if (amt_read == -1) {
4447				warn("error reading data from stdin");
4448				error = 1;
4449				goto scsicmd_bailout;
4450			}
4451			amt_to_read -= amt_read;
4452			buf_ptr += amt_read;
4453		}
4454	}
4455
4456	if (arglist & CAM_ARG_ERR_RECOVER)
4457		flags |= CAM_PASS_ERR_RECOVER;
4458
4459	/* Disable freezing the device queue */
4460	flags |= CAM_DEV_QFRZDIS;
4461
4462	if (cdb_len) {
4463		/*
4464		 * This is taken from the SCSI-3 draft spec.
4465		 * (T10/1157D revision 0.3)
4466		 * The top 3 bits of an opcode are the group code.
4467		 * The next 5 bits are the command code.
4468		 * Group 0:  six byte commands
4469		 * Group 1:  ten byte commands
4470		 * Group 2:  ten byte commands
4471		 * Group 3:  reserved
4472		 * Group 4:  sixteen byte commands
4473		 * Group 5:  twelve byte commands
4474		 * Group 6:  vendor specific
4475		 * Group 7:  vendor specific
4476		 */
4477		switch((cdb[0] >> 5) & 0x7) {
4478			case 0:
4479				cdb_len = 6;
4480				break;
4481			case 1:
4482			case 2:
4483				cdb_len = 10;
4484				break;
4485			case 3:
4486			case 6:
4487			case 7:
4488			        /* computed by buff_encode_visit */
4489				break;
4490			case 4:
4491				cdb_len = 16;
4492				break;
4493			case 5:
4494				cdb_len = 12;
4495				break;
4496		}
4497
4498		/*
4499		 * We should probably use csio_build_visit or something like that
4500		 * here, but it's easier to encode arguments as you go.  The
4501		 * alternative would be skipping the CDB argument and then encoding
4502		 * it here, since we've got the data buffer argument by now.
4503		 */
4504		bcopy(cdb, &ccb->csio.cdb_io.cdb_bytes, cdb_len);
4505
4506		cam_fill_csio(&ccb->csio,
4507		      /*retries*/ retry_count,
4508		      /*cbfcnp*/ NULL,
4509		      /*flags*/ flags,
4510		      /*tag_action*/ task_attr,
4511		      /*data_ptr*/ data_ptr,
4512		      /*dxfer_len*/ data_bytes,
4513		      /*sense_len*/ SSD_FULL_SIZE,
4514		      /*cdb_len*/ cdb_len,
4515		      /*timeout*/ timeout ? timeout : 5000);
4516	} else {
4517		atacmd_len = 12;
4518		bcopy(atacmd, &ccb->ataio.cmd.command, atacmd_len);
4519		if (need_res)
4520			ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT;
4521		if (dmacmd)
4522			ccb->ataio.cmd.flags |= CAM_ATAIO_DMA;
4523		if (fpdmacmd)
4524			ccb->ataio.cmd.flags |= CAM_ATAIO_FPDMA;
4525
4526		cam_fill_ataio(&ccb->ataio,
4527		      /*retries*/ retry_count,
4528		      /*cbfcnp*/ NULL,
4529		      /*flags*/ flags,
4530		      /*tag_action*/ 0,
4531		      /*data_ptr*/ data_ptr,
4532		      /*dxfer_len*/ data_bytes,
4533		      /*timeout*/ timeout ? timeout : 5000);
4534	}
4535
4536	if (((retval = cam_send_ccb(device, ccb)) < 0)
4537	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
4538		const char warnstr[] = "error sending command";
4539
4540		if (retval < 0)
4541			warn(warnstr);
4542		else
4543			warnx(warnstr);
4544
4545		if (arglist & CAM_ARG_VERBOSE) {
4546			cam_error_print(device, ccb, CAM_ESF_ALL,
4547					CAM_EPF_ALL, stderr);
4548		}
4549
4550		error = 1;
4551		goto scsicmd_bailout;
4552	}
4553
4554	if (atacmd_len && need_res) {
4555		if (fd_res == 0) {
4556			buff_decode_visit(&ccb->ataio.res.status, 11, resstr,
4557					  arg_put, NULL);
4558			fprintf(stdout, "\n");
4559		} else {
4560			fprintf(stdout,
4561			    "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
4562			    ccb->ataio.res.status,
4563			    ccb->ataio.res.error,
4564			    ccb->ataio.res.lba_low,
4565			    ccb->ataio.res.lba_mid,
4566			    ccb->ataio.res.lba_high,
4567			    ccb->ataio.res.device,
4568			    ccb->ataio.res.lba_low_exp,
4569			    ccb->ataio.res.lba_mid_exp,
4570			    ccb->ataio.res.lba_high_exp,
4571			    ccb->ataio.res.sector_count,
4572			    ccb->ataio.res.sector_count_exp);
4573			fflush(stdout);
4574		}
4575	}
4576
4577	if (cdb_len)
4578		valid_bytes = ccb->csio.dxfer_len - ccb->csio.resid;
4579	else
4580		valid_bytes = ccb->ataio.dxfer_len - ccb->ataio.resid;
4581	if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
4582	 && (arglist & CAM_ARG_CMD_IN)
4583	 && (valid_bytes > 0)) {
4584		if (fd_data == 0) {
4585			buff_decode_visit(data_ptr, valid_bytes, datastr,
4586					  arg_put, NULL);
4587			fprintf(stdout, "\n");
4588		} else {
4589			ssize_t amt_written;
4590			int amt_to_write = valid_bytes;
4591			u_int8_t *buf_ptr = data_ptr;
4592
4593			for (amt_written = 0; (amt_to_write > 0) &&
4594			     (amt_written =write(1, buf_ptr,amt_to_write))> 0;){
4595				amt_to_write -= amt_written;
4596				buf_ptr += amt_written;
4597			}
4598			if (amt_written == -1) {
4599				warn("error writing data to stdout");
4600				error = 1;
4601				goto scsicmd_bailout;
4602			} else if ((amt_written == 0)
4603				&& (amt_to_write > 0)) {
4604				warnx("only wrote %u bytes out of %u",
4605				      valid_bytes - amt_to_write, valid_bytes);
4606			}
4607		}
4608	}
4609
4610scsicmd_bailout:
4611
4612	if ((data_bytes > 0) && (data_ptr != NULL))
4613		free(data_ptr);
4614
4615	cam_freeccb(ccb);
4616
4617	return(error);
4618}
4619
4620static int
4621camdebug(int argc, char **argv, char *combinedopt)
4622{
4623	int c, fd;
4624	path_id_t bus = CAM_BUS_WILDCARD;
4625	target_id_t target = CAM_TARGET_WILDCARD;
4626	lun_id_t lun = CAM_LUN_WILDCARD;
4627	char *tstr, *tmpstr = NULL;
4628	union ccb ccb;
4629	int error = 0;
4630
4631	bzero(&ccb, sizeof(union ccb));
4632
4633	while ((c = getopt(argc, argv, combinedopt)) != -1) {
4634		switch(c) {
4635		case 'I':
4636			arglist |= CAM_ARG_DEBUG_INFO;
4637			ccb.cdbg.flags |= CAM_DEBUG_INFO;
4638			break;
4639		case 'P':
4640			arglist |= CAM_ARG_DEBUG_PERIPH;
4641			ccb.cdbg.flags |= CAM_DEBUG_PERIPH;
4642			break;
4643		case 'S':
4644			arglist |= CAM_ARG_DEBUG_SUBTRACE;
4645			ccb.cdbg.flags |= CAM_DEBUG_SUBTRACE;
4646			break;
4647		case 'T':
4648			arglist |= CAM_ARG_DEBUG_TRACE;
4649			ccb.cdbg.flags |= CAM_DEBUG_TRACE;
4650			break;
4651		case 'X':
4652			arglist |= CAM_ARG_DEBUG_XPT;
4653			ccb.cdbg.flags |= CAM_DEBUG_XPT;
4654			break;
4655		case 'c':
4656			arglist |= CAM_ARG_DEBUG_CDB;
4657			ccb.cdbg.flags |= CAM_DEBUG_CDB;
4658			break;
4659		case 'p':
4660			arglist |= CAM_ARG_DEBUG_PROBE;
4661			ccb.cdbg.flags |= CAM_DEBUG_PROBE;
4662			break;
4663		default:
4664			break;
4665		}
4666	}
4667
4668	if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
4669		warnx("error opening transport layer device %s", XPT_DEVICE);
4670		warn("%s", XPT_DEVICE);
4671		return(1);
4672	}
4673	argc -= optind;
4674	argv += optind;
4675
4676	if (argc <= 0) {
4677		warnx("you must specify \"off\", \"all\" or a bus,");
4678		warnx("bus:target, or bus:target:lun");
4679		close(fd);
4680		return(1);
4681	}
4682
4683	tstr = *argv;
4684
4685	while (isspace(*tstr) && (*tstr != '\0'))
4686		tstr++;
4687
4688	if (strncmp(tstr, "off", 3) == 0) {
4689		ccb.cdbg.flags = CAM_DEBUG_NONE;
4690		arglist &= ~(CAM_ARG_DEBUG_INFO|CAM_ARG_DEBUG_PERIPH|
4691			     CAM_ARG_DEBUG_TRACE|CAM_ARG_DEBUG_SUBTRACE|
4692			     CAM_ARG_DEBUG_XPT|CAM_ARG_DEBUG_PROBE);
4693	} else if (strncmp(tstr, "all", 3) != 0) {
4694		tmpstr = (char *)strtok(tstr, ":");
4695		if ((tmpstr != NULL) && (*tmpstr != '\0')){
4696			bus = strtol(tmpstr, NULL, 0);
4697			arglist |= CAM_ARG_BUS;
4698			tmpstr = (char *)strtok(NULL, ":");
4699			if ((tmpstr != NULL) && (*tmpstr != '\0')){
4700				target = strtol(tmpstr, NULL, 0);
4701				arglist |= CAM_ARG_TARGET;
4702				tmpstr = (char *)strtok(NULL, ":");
4703				if ((tmpstr != NULL) && (*tmpstr != '\0')){
4704					lun = strtol(tmpstr, NULL, 0);
4705					arglist |= CAM_ARG_LUN;
4706				}
4707			}
4708		} else {
4709			error = 1;
4710			warnx("you must specify \"all\", \"off\", or a bus,");
4711			warnx("bus:target, or bus:target:lun to debug");
4712		}
4713	}
4714
4715	if (error == 0) {
4716
4717		ccb.ccb_h.func_code = XPT_DEBUG;
4718		ccb.ccb_h.path_id = bus;
4719		ccb.ccb_h.target_id = target;
4720		ccb.ccb_h.target_lun = lun;
4721
4722		if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
4723			warn("CAMIOCOMMAND ioctl failed");
4724			error = 1;
4725		}
4726
4727		if (error == 0) {
4728			if ((ccb.ccb_h.status & CAM_STATUS_MASK) ==
4729			     CAM_FUNC_NOTAVAIL) {
4730				warnx("CAM debugging not available");
4731				warnx("you need to put options CAMDEBUG in"
4732				      " your kernel config file!");
4733				error = 1;
4734			} else if ((ccb.ccb_h.status & CAM_STATUS_MASK) !=
4735				    CAM_REQ_CMP) {
4736				warnx("XPT_DEBUG CCB failed with status %#x",
4737				      ccb.ccb_h.status);
4738				error = 1;
4739			} else {
4740				if (ccb.cdbg.flags == CAM_DEBUG_NONE) {
4741					fprintf(stderr,
4742						"Debugging turned off\n");
4743				} else {
4744					fprintf(stderr,
4745						"Debugging enabled for "
4746						"%d:%d:%jx\n",
4747						bus, target, (uintmax_t)lun);
4748				}
4749			}
4750		}
4751		close(fd);
4752	}
4753
4754	return(error);
4755}
4756
4757static int
4758tagcontrol(struct cam_device *device, int argc, char **argv,
4759	   char *combinedopt)
4760{
4761	int c;
4762	union ccb *ccb;
4763	int numtags = -1;
4764	int retval = 0;
4765	int quiet = 0;
4766	char pathstr[1024];
4767
4768	ccb = cam_getccb(device);
4769
4770	if (ccb == NULL) {
4771		warnx("tagcontrol: error allocating ccb");
4772		return(1);
4773	}
4774
4775	while ((c = getopt(argc, argv, combinedopt)) != -1) {
4776		switch(c) {
4777		case 'N':
4778			numtags = strtol(optarg, NULL, 0);
4779			if (numtags < 0) {
4780				warnx("tag count %d is < 0", numtags);
4781				retval = 1;
4782				goto tagcontrol_bailout;
4783			}
4784			break;
4785		case 'q':
4786			quiet++;
4787			break;
4788		default:
4789			break;
4790		}
4791	}
4792
4793	cam_path_string(device, pathstr, sizeof(pathstr));
4794
4795	if (numtags >= 0) {
4796		CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->crs);
4797		ccb->ccb_h.func_code = XPT_REL_SIMQ;
4798		ccb->ccb_h.flags = CAM_DEV_QFREEZE;
4799		ccb->crs.release_flags = RELSIM_ADJUST_OPENINGS;
4800		ccb->crs.openings = numtags;
4801
4802
4803		if (cam_send_ccb(device, ccb) < 0) {
4804			perror("error sending XPT_REL_SIMQ CCB");
4805			retval = 1;
4806			goto tagcontrol_bailout;
4807		}
4808
4809		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
4810			warnx("XPT_REL_SIMQ CCB failed");
4811			cam_error_print(device, ccb, CAM_ESF_ALL,
4812					CAM_EPF_ALL, stderr);
4813			retval = 1;
4814			goto tagcontrol_bailout;
4815		}
4816
4817
4818		if (quiet == 0)
4819			fprintf(stdout, "%stagged openings now %d\n",
4820				pathstr, ccb->crs.openings);
4821	}
4822
4823	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->cgds);
4824
4825	ccb->ccb_h.func_code = XPT_GDEV_STATS;
4826
4827	if (cam_send_ccb(device, ccb) < 0) {
4828		perror("error sending XPT_GDEV_STATS CCB");
4829		retval = 1;
4830		goto tagcontrol_bailout;
4831	}
4832
4833	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
4834		warnx("XPT_GDEV_STATS CCB failed");
4835		cam_error_print(device, ccb, CAM_ESF_ALL,
4836				CAM_EPF_ALL, stderr);
4837		retval = 1;
4838		goto tagcontrol_bailout;
4839	}
4840
4841	if (arglist & CAM_ARG_VERBOSE) {
4842		fprintf(stdout, "%s", pathstr);
4843		fprintf(stdout, "dev_openings  %d\n", ccb->cgds.dev_openings);
4844		fprintf(stdout, "%s", pathstr);
4845		fprintf(stdout, "dev_active    %d\n", ccb->cgds.dev_active);
4846		fprintf(stdout, "%s", pathstr);
4847		fprintf(stdout, "allocated     %d\n", ccb->cgds.allocated);
4848		fprintf(stdout, "%s", pathstr);
4849		fprintf(stdout, "queued        %d\n", ccb->cgds.queued);
4850		fprintf(stdout, "%s", pathstr);
4851		fprintf(stdout, "held          %d\n", ccb->cgds.held);
4852		fprintf(stdout, "%s", pathstr);
4853		fprintf(stdout, "mintags       %d\n", ccb->cgds.mintags);
4854		fprintf(stdout, "%s", pathstr);
4855		fprintf(stdout, "maxtags       %d\n", ccb->cgds.maxtags);
4856	} else {
4857		if (quiet == 0) {
4858			fprintf(stdout, "%s", pathstr);
4859			fprintf(stdout, "device openings: ");
4860		}
4861		fprintf(stdout, "%d\n", ccb->cgds.dev_openings +
4862			ccb->cgds.dev_active);
4863	}
4864
4865tagcontrol_bailout:
4866
4867	cam_freeccb(ccb);
4868	return(retval);
4869}
4870
4871static void
4872cts_print(struct cam_device *device, struct ccb_trans_settings *cts)
4873{
4874	char pathstr[1024];
4875
4876	cam_path_string(device, pathstr, sizeof(pathstr));
4877
4878	if (cts->transport == XPORT_SPI) {
4879		struct ccb_trans_settings_spi *spi =
4880		    &cts->xport_specific.spi;
4881
4882		if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) {
4883
4884			fprintf(stdout, "%ssync parameter: %d\n", pathstr,
4885				spi->sync_period);
4886
4887			if (spi->sync_offset != 0) {
4888				u_int freq;
4889
4890				freq = scsi_calc_syncsrate(spi->sync_period);
4891				fprintf(stdout, "%sfrequency: %d.%03dMHz\n",
4892					pathstr, freq / 1000, freq % 1000);
4893			}
4894		}
4895
4896		if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) {
4897			fprintf(stdout, "%soffset: %d\n", pathstr,
4898			    spi->sync_offset);
4899		}
4900
4901		if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) {
4902			fprintf(stdout, "%sbus width: %d bits\n", pathstr,
4903				(0x01 << spi->bus_width) * 8);
4904		}
4905
4906		if (spi->valid & CTS_SPI_VALID_DISC) {
4907			fprintf(stdout, "%sdisconnection is %s\n", pathstr,
4908				(spi->flags & CTS_SPI_FLAGS_DISC_ENB) ?
4909				"enabled" : "disabled");
4910		}
4911	}
4912	if (cts->transport == XPORT_FC) {
4913		struct ccb_trans_settings_fc *fc =
4914		    &cts->xport_specific.fc;
4915
4916		if (fc->valid & CTS_FC_VALID_WWNN)
4917			fprintf(stdout, "%sWWNN: 0x%llx\n", pathstr,
4918			    (long long) fc->wwnn);
4919		if (fc->valid & CTS_FC_VALID_WWPN)
4920			fprintf(stdout, "%sWWPN: 0x%llx\n", pathstr,
4921			    (long long) fc->wwpn);
4922		if (fc->valid & CTS_FC_VALID_PORT)
4923			fprintf(stdout, "%sPortID: 0x%x\n", pathstr, fc->port);
4924		if (fc->valid & CTS_FC_VALID_SPEED)
4925			fprintf(stdout, "%stransfer speed: %d.%03dMB/s\n",
4926			    pathstr, fc->bitrate / 1000, fc->bitrate % 1000);
4927	}
4928	if (cts->transport == XPORT_SAS) {
4929		struct ccb_trans_settings_sas *sas =
4930		    &cts->xport_specific.sas;
4931
4932		if (sas->valid & CTS_SAS_VALID_SPEED)
4933			fprintf(stdout, "%stransfer speed: %d.%03dMB/s\n",
4934			    pathstr, sas->bitrate / 1000, sas->bitrate % 1000);
4935	}
4936	if (cts->transport == XPORT_ATA) {
4937		struct ccb_trans_settings_pata *pata =
4938		    &cts->xport_specific.ata;
4939
4940		if ((pata->valid & CTS_ATA_VALID_MODE) != 0) {
4941			fprintf(stdout, "%sATA mode: %s\n", pathstr,
4942				ata_mode2string(pata->mode));
4943		}
4944		if ((pata->valid & CTS_ATA_VALID_ATAPI) != 0) {
4945			fprintf(stdout, "%sATAPI packet length: %d\n", pathstr,
4946				pata->atapi);
4947		}
4948		if ((pata->valid & CTS_ATA_VALID_BYTECOUNT) != 0) {
4949			fprintf(stdout, "%sPIO transaction length: %d\n",
4950				pathstr, pata->bytecount);
4951		}
4952	}
4953	if (cts->transport == XPORT_SATA) {
4954		struct ccb_trans_settings_sata *sata =
4955		    &cts->xport_specific.sata;
4956
4957		if ((sata->valid & CTS_SATA_VALID_REVISION) != 0) {
4958			fprintf(stdout, "%sSATA revision: %d.x\n", pathstr,
4959				sata->revision);
4960		}
4961		if ((sata->valid & CTS_SATA_VALID_MODE) != 0) {
4962			fprintf(stdout, "%sATA mode: %s\n", pathstr,
4963				ata_mode2string(sata->mode));
4964		}
4965		if ((sata->valid & CTS_SATA_VALID_ATAPI) != 0) {
4966			fprintf(stdout, "%sATAPI packet length: %d\n", pathstr,
4967				sata->atapi);
4968		}
4969		if ((sata->valid & CTS_SATA_VALID_BYTECOUNT) != 0) {
4970			fprintf(stdout, "%sPIO transaction length: %d\n",
4971				pathstr, sata->bytecount);
4972		}
4973		if ((sata->valid & CTS_SATA_VALID_PM) != 0) {
4974			fprintf(stdout, "%sPMP presence: %d\n", pathstr,
4975				sata->pm_present);
4976		}
4977		if ((sata->valid & CTS_SATA_VALID_TAGS) != 0) {
4978			fprintf(stdout, "%sNumber of tags: %d\n", pathstr,
4979				sata->tags);
4980		}
4981		if ((sata->valid & CTS_SATA_VALID_CAPS) != 0) {
4982			fprintf(stdout, "%sSATA capabilities: %08x\n", pathstr,
4983				sata->caps);
4984		}
4985	}
4986	if (cts->protocol == PROTO_ATA) {
4987		struct ccb_trans_settings_ata *ata=
4988		    &cts->proto_specific.ata;
4989
4990		if (ata->valid & CTS_ATA_VALID_TQ) {
4991			fprintf(stdout, "%stagged queueing: %s\n", pathstr,
4992				(ata->flags & CTS_ATA_FLAGS_TAG_ENB) ?
4993				"enabled" : "disabled");
4994		}
4995	}
4996	if (cts->protocol == PROTO_SCSI) {
4997		struct ccb_trans_settings_scsi *scsi=
4998		    &cts->proto_specific.scsi;
4999
5000		if (scsi->valid & CTS_SCSI_VALID_TQ) {
5001			fprintf(stdout, "%stagged queueing: %s\n", pathstr,
5002				(scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) ?
5003				"enabled" : "disabled");
5004		}
5005	}
5006
5007}
5008
5009/*
5010 * Get a path inquiry CCB for the specified device.
5011 */
5012static int
5013get_cpi(struct cam_device *device, struct ccb_pathinq *cpi)
5014{
5015	union ccb *ccb;
5016	int retval = 0;
5017
5018	ccb = cam_getccb(device);
5019	if (ccb == NULL) {
5020		warnx("get_cpi: couldn't allocate CCB");
5021		return(1);
5022	}
5023	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->cpi);
5024	ccb->ccb_h.func_code = XPT_PATH_INQ;
5025	if (cam_send_ccb(device, ccb) < 0) {
5026		warn("get_cpi: error sending Path Inquiry CCB");
5027		if (arglist & CAM_ARG_VERBOSE)
5028			cam_error_print(device, ccb, CAM_ESF_ALL,
5029					CAM_EPF_ALL, stderr);
5030		retval = 1;
5031		goto get_cpi_bailout;
5032	}
5033	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
5034		if (arglist & CAM_ARG_VERBOSE)
5035			cam_error_print(device, ccb, CAM_ESF_ALL,
5036					CAM_EPF_ALL, stderr);
5037		retval = 1;
5038		goto get_cpi_bailout;
5039	}
5040	bcopy(&ccb->cpi, cpi, sizeof(struct ccb_pathinq));
5041
5042get_cpi_bailout:
5043	cam_freeccb(ccb);
5044	return(retval);
5045}
5046
5047/*
5048 * Get a get device CCB for the specified device.
5049 */
5050static int
5051get_cgd(struct cam_device *device, struct ccb_getdev *cgd)
5052{
5053	union ccb *ccb;
5054	int retval = 0;
5055
5056	ccb = cam_getccb(device);
5057	if (ccb == NULL) {
5058		warnx("get_cgd: couldn't allocate CCB");
5059		return(1);
5060	}
5061	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->cgd);
5062	ccb->ccb_h.func_code = XPT_GDEV_TYPE;
5063	if (cam_send_ccb(device, ccb) < 0) {
5064		warn("get_cgd: error sending Path Inquiry CCB");
5065		if (arglist & CAM_ARG_VERBOSE)
5066			cam_error_print(device, ccb, CAM_ESF_ALL,
5067					CAM_EPF_ALL, stderr);
5068		retval = 1;
5069		goto get_cgd_bailout;
5070	}
5071	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
5072		if (arglist & CAM_ARG_VERBOSE)
5073			cam_error_print(device, ccb, CAM_ESF_ALL,
5074					CAM_EPF_ALL, stderr);
5075		retval = 1;
5076		goto get_cgd_bailout;
5077	}
5078	bcopy(&ccb->cgd, cgd, sizeof(struct ccb_getdev));
5079
5080get_cgd_bailout:
5081	cam_freeccb(ccb);
5082	return(retval);
5083}
5084
5085/*
5086 * Returns 1 if the device has the VPD page, 0 if it does not, and -1 on an
5087 * error.
5088 */
5089int
5090dev_has_vpd_page(struct cam_device *dev, uint8_t page_id, int retry_count,
5091		 int timeout, int verbosemode)
5092{
5093	union ccb *ccb = NULL;
5094	struct scsi_vpd_supported_page_list sup_pages;
5095	int i;
5096	int retval = 0;
5097
5098	ccb = cam_getccb(dev);
5099	if (ccb == NULL) {
5100		warn("Unable to allocate CCB");
5101		retval = -1;
5102		goto bailout;
5103	}
5104
5105	/* cam_getccb cleans up the header, caller has to zero the payload */
5106	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
5107
5108	bzero(&sup_pages, sizeof(sup_pages));
5109
5110	scsi_inquiry(&ccb->csio,
5111		     /*retries*/ retry_count,
5112		     /*cbfcnp*/ NULL,
5113		     /* tag_action */ MSG_SIMPLE_Q_TAG,
5114		     /* inq_buf */ (u_int8_t *)&sup_pages,
5115		     /* inq_len */ sizeof(sup_pages),
5116		     /* evpd */ 1,
5117		     /* page_code */ SVPD_SUPPORTED_PAGE_LIST,
5118		     /* sense_len */ SSD_FULL_SIZE,
5119		     /* timeout */ timeout ? timeout : 5000);
5120
5121	/* Disable freezing the device queue */
5122	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
5123
5124	if (retry_count != 0)
5125		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
5126
5127	if (cam_send_ccb(dev, ccb) < 0) {
5128		cam_freeccb(ccb);
5129		ccb = NULL;
5130		retval = -1;
5131		goto bailout;
5132	}
5133
5134	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
5135		if (verbosemode != 0)
5136			cam_error_print(dev, ccb, CAM_ESF_ALL,
5137					CAM_EPF_ALL, stderr);
5138		retval = -1;
5139		goto bailout;
5140	}
5141
5142	for (i = 0; i < sup_pages.length; i++) {
5143		if (sup_pages.list[i] == page_id) {
5144			retval = 1;
5145			goto bailout;
5146		}
5147	}
5148bailout:
5149	if (ccb != NULL)
5150		cam_freeccb(ccb);
5151
5152	return (retval);
5153}
5154
5155/*
5156 * devtype is filled in with the type of device.
5157 * Returns 0 for success, non-zero for failure.
5158 */
5159int
5160get_device_type(struct cam_device *dev, int retry_count, int timeout,
5161		    int verbosemode, camcontrol_devtype *devtype)
5162{
5163	struct ccb_getdev cgd;
5164	int retval = 0;
5165
5166	retval = get_cgd(dev, &cgd);
5167	if (retval != 0)
5168		goto bailout;
5169
5170	switch (cgd.protocol) {
5171	case PROTO_SCSI:
5172		break;
5173	case PROTO_ATA:
5174	case PROTO_ATAPI:
5175	case PROTO_SATAPM:
5176		*devtype = CC_DT_ATA;
5177		goto bailout;
5178		break; /*NOTREACHED*/
5179	default:
5180		*devtype = CC_DT_UNKNOWN;
5181		goto bailout;
5182		break; /*NOTREACHED*/
5183	}
5184
5185	/*
5186	 * Check for the ATA Information VPD page (0x89).  If this is an
5187	 * ATA device behind a SCSI to ATA translation layer, this VPD page
5188	 * should be present.
5189	 *
5190	 * If that VPD page isn't present, or we get an error back from the
5191	 * INQUIRY command, we'll just treat it as a normal SCSI device.
5192	 */
5193	retval = dev_has_vpd_page(dev, SVPD_ATA_INFORMATION, retry_count,
5194				  timeout, verbosemode);
5195	if (retval == 1)
5196		*devtype = CC_DT_ATA_BEHIND_SCSI;
5197	else
5198		*devtype = CC_DT_SCSI;
5199
5200	retval = 0;
5201
5202bailout:
5203	return (retval);
5204}
5205
5206void
5207build_ata_cmd(union ccb *ccb, uint32_t retry_count, uint32_t flags,
5208    uint8_t tag_action, uint8_t protocol, uint8_t ata_flags, uint16_t features,
5209    uint16_t sector_count, uint64_t lba, uint8_t command, uint8_t *data_ptr,
5210    uint16_t dxfer_len, uint8_t sense_len, uint32_t timeout,
5211    int is48bit, camcontrol_devtype devtype)
5212{
5213	if (devtype == CC_DT_ATA) {
5214		cam_fill_ataio(&ccb->ataio,
5215		    /*retries*/ retry_count,
5216		    /*cbfcnp*/ NULL,
5217		    /*flags*/ flags,
5218		    /*tag_action*/ tag_action,
5219		    /*data_ptr*/ data_ptr,
5220		    /*dxfer_len*/ dxfer_len,
5221		    /*timeout*/ timeout);
5222		if (is48bit || lba > ATA_MAX_28BIT_LBA)
5223			ata_48bit_cmd(&ccb->ataio, command, features, lba,
5224			    sector_count);
5225		else
5226			ata_28bit_cmd(&ccb->ataio, command, features, lba,
5227			    sector_count);
5228	} else {
5229		if (is48bit || lba > ATA_MAX_28BIT_LBA)
5230			protocol |= AP_EXTEND;
5231
5232		scsi_ata_pass_16(&ccb->csio,
5233		    /*retries*/ retry_count,
5234		    /*cbfcnp*/ NULL,
5235		    /*flags*/ flags,
5236		    /*tag_action*/ tag_action,
5237		    /*protocol*/ protocol,
5238		    /*ata_flags*/ ata_flags,
5239		    /*features*/ features,
5240		    /*sector_count*/ sector_count,
5241		    /*lba*/ lba,
5242		    /*command*/ command,
5243		    /*control*/ 0,
5244		    /*data_ptr*/ data_ptr,
5245		    /*dxfer_len*/ dxfer_len,
5246		    /*sense_len*/ sense_len,
5247		    /*timeout*/ timeout);
5248	}
5249}
5250
5251
5252static void
5253cpi_print(struct ccb_pathinq *cpi)
5254{
5255	char adapter_str[1024];
5256	uint64_t i;
5257
5258	snprintf(adapter_str, sizeof(adapter_str),
5259		 "%s%d:", cpi->dev_name, cpi->unit_number);
5260
5261	fprintf(stdout, "%s SIM/HBA version: %d\n", adapter_str,
5262		cpi->version_num);
5263
5264	for (i = 1; i < UINT8_MAX; i = i << 1) {
5265		const char *str;
5266
5267		if ((i & cpi->hba_inquiry) == 0)
5268			continue;
5269
5270		fprintf(stdout, "%s supports ", adapter_str);
5271
5272		switch(i) {
5273		case PI_MDP_ABLE:
5274			str = "MDP message";
5275			break;
5276		case PI_WIDE_32:
5277			str = "32 bit wide SCSI";
5278			break;
5279		case PI_WIDE_16:
5280			str = "16 bit wide SCSI";
5281			break;
5282		case PI_SDTR_ABLE:
5283			str = "SDTR message";
5284			break;
5285		case PI_LINKED_CDB:
5286			str = "linked CDBs";
5287			break;
5288		case PI_TAG_ABLE:
5289			str = "tag queue messages";
5290			break;
5291		case PI_SOFT_RST:
5292			str = "soft reset alternative";
5293			break;
5294		case PI_SATAPM:
5295			str = "SATA Port Multiplier";
5296			break;
5297		default:
5298			str = "unknown PI bit set";
5299			break;
5300		}
5301		fprintf(stdout, "%s\n", str);
5302	}
5303
5304	for (i = 1; i < UINT32_MAX; i = i << 1) {
5305		const char *str;
5306
5307		if ((i & cpi->hba_misc) == 0)
5308			continue;
5309
5310		fprintf(stdout, "%s ", adapter_str);
5311
5312		switch(i) {
5313		case PIM_SCANHILO:
5314			str = "bus scans from high ID to low ID";
5315			break;
5316		case PIM_NOREMOVE:
5317			str = "removable devices not included in scan";
5318			break;
5319		case PIM_NOINITIATOR:
5320			str = "initiator role not supported";
5321			break;
5322		case PIM_NOBUSRESET:
5323			str = "user has disabled initial BUS RESET or"
5324			      " controller is in target/mixed mode";
5325			break;
5326		case PIM_NO_6_BYTE:
5327			str = "do not send 6-byte commands";
5328			break;
5329		case PIM_SEQSCAN:
5330			str = "scan bus sequentially";
5331			break;
5332		default:
5333			str = "unknown PIM bit set";
5334			break;
5335		}
5336		fprintf(stdout, "%s\n", str);
5337	}
5338
5339	for (i = 1; i < UINT16_MAX; i = i << 1) {
5340		const char *str;
5341
5342		if ((i & cpi->target_sprt) == 0)
5343			continue;
5344
5345		fprintf(stdout, "%s supports ", adapter_str);
5346		switch(i) {
5347		case PIT_PROCESSOR:
5348			str = "target mode processor mode";
5349			break;
5350		case PIT_PHASE:
5351			str = "target mode phase cog. mode";
5352			break;
5353		case PIT_DISCONNECT:
5354			str = "disconnects in target mode";
5355			break;
5356		case PIT_TERM_IO:
5357			str = "terminate I/O message in target mode";
5358			break;
5359		case PIT_GRP_6:
5360			str = "group 6 commands in target mode";
5361			break;
5362		case PIT_GRP_7:
5363			str = "group 7 commands in target mode";
5364			break;
5365		default:
5366			str = "unknown PIT bit set";
5367			break;
5368		}
5369
5370		fprintf(stdout, "%s\n", str);
5371	}
5372	fprintf(stdout, "%s HBA engine count: %d\n", adapter_str,
5373		cpi->hba_eng_cnt);
5374	fprintf(stdout, "%s maximum target: %d\n", adapter_str,
5375		cpi->max_target);
5376	fprintf(stdout, "%s maximum LUN: %d\n", adapter_str,
5377		cpi->max_lun);
5378	fprintf(stdout, "%s highest path ID in subsystem: %d\n",
5379		adapter_str, cpi->hpath_id);
5380	fprintf(stdout, "%s initiator ID: %d\n", adapter_str,
5381		cpi->initiator_id);
5382	fprintf(stdout, "%s SIM vendor: %s\n", adapter_str, cpi->sim_vid);
5383	fprintf(stdout, "%s HBA vendor: %s\n", adapter_str, cpi->hba_vid);
5384	fprintf(stdout, "%s HBA vendor ID: 0x%04x\n",
5385	    adapter_str, cpi->hba_vendor);
5386	fprintf(stdout, "%s HBA device ID: 0x%04x\n",
5387	    adapter_str, cpi->hba_device);
5388	fprintf(stdout, "%s HBA subvendor ID: 0x%04x\n",
5389	    adapter_str, cpi->hba_subvendor);
5390	fprintf(stdout, "%s HBA subdevice ID: 0x%04x\n",
5391	    adapter_str, cpi->hba_subdevice);
5392	fprintf(stdout, "%s bus ID: %d\n", adapter_str, cpi->bus_id);
5393	fprintf(stdout, "%s base transfer speed: ", adapter_str);
5394	if (cpi->base_transfer_speed > 1000)
5395		fprintf(stdout, "%d.%03dMB/sec\n",
5396			cpi->base_transfer_speed / 1000,
5397			cpi->base_transfer_speed % 1000);
5398	else
5399		fprintf(stdout, "%dKB/sec\n",
5400			(cpi->base_transfer_speed % 1000) * 1000);
5401	fprintf(stdout, "%s maximum transfer size: %u bytes\n",
5402	    adapter_str, cpi->maxio);
5403}
5404
5405static int
5406get_print_cts(struct cam_device *device, int user_settings, int quiet,
5407	      struct ccb_trans_settings *cts)
5408{
5409	int retval;
5410	union ccb *ccb;
5411
5412	retval = 0;
5413	ccb = cam_getccb(device);
5414
5415	if (ccb == NULL) {
5416		warnx("get_print_cts: error allocating ccb");
5417		return(1);
5418	}
5419
5420	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->cts);
5421
5422	ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
5423
5424	if (user_settings == 0)
5425		ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS;
5426	else
5427		ccb->cts.type = CTS_TYPE_USER_SETTINGS;
5428
5429	if (cam_send_ccb(device, ccb) < 0) {
5430		perror("error sending XPT_GET_TRAN_SETTINGS CCB");
5431		if (arglist & CAM_ARG_VERBOSE)
5432			cam_error_print(device, ccb, CAM_ESF_ALL,
5433					CAM_EPF_ALL, stderr);
5434		retval = 1;
5435		goto get_print_cts_bailout;
5436	}
5437
5438	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
5439		warnx("XPT_GET_TRANS_SETTINGS CCB failed");
5440		if (arglist & CAM_ARG_VERBOSE)
5441			cam_error_print(device, ccb, CAM_ESF_ALL,
5442					CAM_EPF_ALL, stderr);
5443		retval = 1;
5444		goto get_print_cts_bailout;
5445	}
5446
5447	if (quiet == 0)
5448		cts_print(device, &ccb->cts);
5449
5450	if (cts != NULL)
5451		bcopy(&ccb->cts, cts, sizeof(struct ccb_trans_settings));
5452
5453get_print_cts_bailout:
5454
5455	cam_freeccb(ccb);
5456
5457	return(retval);
5458}
5459
5460static int
5461ratecontrol(struct cam_device *device, int task_attr, int retry_count,
5462	    int timeout, int argc, char **argv, char *combinedopt)
5463{
5464	int c;
5465	union ccb *ccb;
5466	int user_settings = 0;
5467	int retval = 0;
5468	int disc_enable = -1, tag_enable = -1;
5469	int mode = -1;
5470	int offset = -1;
5471	double syncrate = -1;
5472	int bus_width = -1;
5473	int quiet = 0;
5474	int change_settings = 0, send_tur = 0;
5475	struct ccb_pathinq cpi;
5476
5477	ccb = cam_getccb(device);
5478	if (ccb == NULL) {
5479		warnx("ratecontrol: error allocating ccb");
5480		return(1);
5481	}
5482	while ((c = getopt(argc, argv, combinedopt)) != -1) {
5483		switch(c){
5484		case 'a':
5485			send_tur = 1;
5486			break;
5487		case 'c':
5488			user_settings = 0;
5489			break;
5490		case 'D':
5491			if (strncasecmp(optarg, "enable", 6) == 0)
5492				disc_enable = 1;
5493			else if (strncasecmp(optarg, "disable", 7) == 0)
5494				disc_enable = 0;
5495			else {
5496				warnx("-D argument \"%s\" is unknown", optarg);
5497				retval = 1;
5498				goto ratecontrol_bailout;
5499			}
5500			change_settings = 1;
5501			break;
5502		case 'M':
5503			mode = ata_string2mode(optarg);
5504			if (mode < 0) {
5505				warnx("unknown mode '%s'", optarg);
5506				retval = 1;
5507				goto ratecontrol_bailout;
5508			}
5509			change_settings = 1;
5510			break;
5511		case 'O':
5512			offset = strtol(optarg, NULL, 0);
5513			if (offset < 0) {
5514				warnx("offset value %d is < 0", offset);
5515				retval = 1;
5516				goto ratecontrol_bailout;
5517			}
5518			change_settings = 1;
5519			break;
5520		case 'q':
5521			quiet++;
5522			break;
5523		case 'R':
5524			syncrate = atof(optarg);
5525			if (syncrate < 0) {
5526				warnx("sync rate %f is < 0", syncrate);
5527				retval = 1;
5528				goto ratecontrol_bailout;
5529			}
5530			change_settings = 1;
5531			break;
5532		case 'T':
5533			if (strncasecmp(optarg, "enable", 6) == 0)
5534				tag_enable = 1;
5535			else if (strncasecmp(optarg, "disable", 7) == 0)
5536				tag_enable = 0;
5537			else {
5538				warnx("-T argument \"%s\" is unknown", optarg);
5539				retval = 1;
5540				goto ratecontrol_bailout;
5541			}
5542			change_settings = 1;
5543			break;
5544		case 'U':
5545			user_settings = 1;
5546			break;
5547		case 'W':
5548			bus_width = strtol(optarg, NULL, 0);
5549			if (bus_width < 0) {
5550				warnx("bus width %d is < 0", bus_width);
5551				retval = 1;
5552				goto ratecontrol_bailout;
5553			}
5554			change_settings = 1;
5555			break;
5556		default:
5557			break;
5558		}
5559	}
5560	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->cpi);
5561	/*
5562	 * Grab path inquiry information, so we can determine whether
5563	 * or not the initiator is capable of the things that the user
5564	 * requests.
5565	 */
5566	ccb->ccb_h.func_code = XPT_PATH_INQ;
5567	if (cam_send_ccb(device, ccb) < 0) {
5568		perror("error sending XPT_PATH_INQ CCB");
5569		if (arglist & CAM_ARG_VERBOSE) {
5570			cam_error_print(device, ccb, CAM_ESF_ALL,
5571					CAM_EPF_ALL, stderr);
5572		}
5573		retval = 1;
5574		goto ratecontrol_bailout;
5575	}
5576	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
5577		warnx("XPT_PATH_INQ CCB failed");
5578		if (arglist & CAM_ARG_VERBOSE) {
5579			cam_error_print(device, ccb, CAM_ESF_ALL,
5580					CAM_EPF_ALL, stderr);
5581		}
5582		retval = 1;
5583		goto ratecontrol_bailout;
5584	}
5585	bcopy(&ccb->cpi, &cpi, sizeof(struct ccb_pathinq));
5586	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->cts);
5587	if (quiet == 0) {
5588		fprintf(stdout, "%s parameters:\n",
5589		    user_settings ? "User" : "Current");
5590	}
5591	retval = get_print_cts(device, user_settings, quiet, &ccb->cts);
5592	if (retval != 0)
5593		goto ratecontrol_bailout;
5594
5595	if (arglist & CAM_ARG_VERBOSE)
5596		cpi_print(&cpi);
5597
5598	if (change_settings) {
5599		int didsettings = 0;
5600		struct ccb_trans_settings_spi *spi = NULL;
5601		struct ccb_trans_settings_pata *pata = NULL;
5602		struct ccb_trans_settings_sata *sata = NULL;
5603		struct ccb_trans_settings_ata *ata = NULL;
5604		struct ccb_trans_settings_scsi *scsi = NULL;
5605
5606		if (ccb->cts.transport == XPORT_SPI)
5607			spi = &ccb->cts.xport_specific.spi;
5608		if (ccb->cts.transport == XPORT_ATA)
5609			pata = &ccb->cts.xport_specific.ata;
5610		if (ccb->cts.transport == XPORT_SATA)
5611			sata = &ccb->cts.xport_specific.sata;
5612		if (ccb->cts.protocol == PROTO_ATA)
5613			ata = &ccb->cts.proto_specific.ata;
5614		if (ccb->cts.protocol == PROTO_SCSI)
5615			scsi = &ccb->cts.proto_specific.scsi;
5616		ccb->cts.xport_specific.valid = 0;
5617		ccb->cts.proto_specific.valid = 0;
5618		if (spi && disc_enable != -1) {
5619			spi->valid |= CTS_SPI_VALID_DISC;
5620			if (disc_enable == 0)
5621				spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
5622			else
5623				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
5624			didsettings++;
5625		}
5626		if (tag_enable != -1) {
5627			if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0) {
5628				warnx("HBA does not support tagged queueing, "
5629				      "so you cannot modify tag settings");
5630				retval = 1;
5631				goto ratecontrol_bailout;
5632			}
5633			if (ata) {
5634				ata->valid |= CTS_SCSI_VALID_TQ;
5635				if (tag_enable == 0)
5636					ata->flags &= ~CTS_ATA_FLAGS_TAG_ENB;
5637				else
5638					ata->flags |= CTS_ATA_FLAGS_TAG_ENB;
5639				didsettings++;
5640			} else if (scsi) {
5641				scsi->valid |= CTS_SCSI_VALID_TQ;
5642				if (tag_enable == 0)
5643					scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
5644				else
5645					scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
5646				didsettings++;
5647			}
5648		}
5649		if (spi && offset != -1) {
5650			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
5651				warnx("HBA is not capable of changing offset");
5652				retval = 1;
5653				goto ratecontrol_bailout;
5654			}
5655			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
5656			spi->sync_offset = offset;
5657			didsettings++;
5658		}
5659		if (spi && syncrate != -1) {
5660			int prelim_sync_period;
5661
5662			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
5663				warnx("HBA is not capable of changing "
5664				      "transfer rates");
5665				retval = 1;
5666				goto ratecontrol_bailout;
5667			}
5668			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
5669			/*
5670			 * The sync rate the user gives us is in MHz.
5671			 * We need to translate it into KHz for this
5672			 * calculation.
5673			 */
5674			syncrate *= 1000;
5675			/*
5676			 * Next, we calculate a "preliminary" sync period
5677			 * in tenths of a nanosecond.
5678			 */
5679			if (syncrate == 0)
5680				prelim_sync_period = 0;
5681			else
5682				prelim_sync_period = 10000000 / syncrate;
5683			spi->sync_period =
5684				scsi_calc_syncparam(prelim_sync_period);
5685			didsettings++;
5686		}
5687		if (sata && syncrate != -1) {
5688			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
5689				warnx("HBA is not capable of changing "
5690				      "transfer rates");
5691				retval = 1;
5692				goto ratecontrol_bailout;
5693			}
5694			if  (!user_settings) {
5695				warnx("You can modify only user rate "
5696				    "settings for SATA");
5697				retval = 1;
5698				goto ratecontrol_bailout;
5699			}
5700			sata->revision = ata_speed2revision(syncrate * 100);
5701			if (sata->revision < 0) {
5702				warnx("Invalid rate %f", syncrate);
5703				retval = 1;
5704				goto ratecontrol_bailout;
5705			}
5706			sata->valid |= CTS_SATA_VALID_REVISION;
5707			didsettings++;
5708		}
5709		if ((pata || sata) && mode != -1) {
5710			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
5711				warnx("HBA is not capable of changing "
5712				      "transfer rates");
5713				retval = 1;
5714				goto ratecontrol_bailout;
5715			}
5716			if  (!user_settings) {
5717				warnx("You can modify only user mode "
5718				    "settings for ATA/SATA");
5719				retval = 1;
5720				goto ratecontrol_bailout;
5721			}
5722			if (pata) {
5723				pata->mode = mode;
5724				pata->valid |= CTS_ATA_VALID_MODE;
5725			} else {
5726				sata->mode = mode;
5727				sata->valid |= CTS_SATA_VALID_MODE;
5728			}
5729			didsettings++;
5730		}
5731		/*
5732		 * The bus_width argument goes like this:
5733		 * 0 == 8 bit
5734		 * 1 == 16 bit
5735		 * 2 == 32 bit
5736		 * Therefore, if you shift the number of bits given on the
5737		 * command line right by 4, you should get the correct
5738		 * number.
5739		 */
5740		if (spi && bus_width != -1) {
5741			/*
5742			 * We might as well validate things here with a
5743			 * decipherable error message, rather than what
5744			 * will probably be an indecipherable error message
5745			 * by the time it gets back to us.
5746			 */
5747			if ((bus_width == 16)
5748			 && ((cpi.hba_inquiry & PI_WIDE_16) == 0)) {
5749				warnx("HBA does not support 16 bit bus width");
5750				retval = 1;
5751				goto ratecontrol_bailout;
5752			} else if ((bus_width == 32)
5753				&& ((cpi.hba_inquiry & PI_WIDE_32) == 0)) {
5754				warnx("HBA does not support 32 bit bus width");
5755				retval = 1;
5756				goto ratecontrol_bailout;
5757			} else if ((bus_width != 8)
5758				&& (bus_width != 16)
5759				&& (bus_width != 32)) {
5760				warnx("Invalid bus width %d", bus_width);
5761				retval = 1;
5762				goto ratecontrol_bailout;
5763			}
5764			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
5765			spi->bus_width = bus_width >> 4;
5766			didsettings++;
5767		}
5768		if  (didsettings == 0) {
5769			goto ratecontrol_bailout;
5770		}
5771		ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
5772		if (cam_send_ccb(device, ccb) < 0) {
5773			perror("error sending XPT_SET_TRAN_SETTINGS CCB");
5774			if (arglist & CAM_ARG_VERBOSE) {
5775				cam_error_print(device, ccb, CAM_ESF_ALL,
5776						CAM_EPF_ALL, stderr);
5777			}
5778			retval = 1;
5779			goto ratecontrol_bailout;
5780		}
5781		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
5782			warnx("XPT_SET_TRANS_SETTINGS CCB failed");
5783			if (arglist & CAM_ARG_VERBOSE) {
5784				cam_error_print(device, ccb, CAM_ESF_ALL,
5785						CAM_EPF_ALL, stderr);
5786			}
5787			retval = 1;
5788			goto ratecontrol_bailout;
5789		}
5790	}
5791	if (send_tur) {
5792		retval = testunitready(device, task_attr, retry_count, timeout,
5793				       (arglist & CAM_ARG_VERBOSE) ? 0 : 1);
5794		/*
5795		 * If the TUR didn't succeed, just bail.
5796		 */
5797		if (retval != 0) {
5798			if (quiet == 0)
5799				fprintf(stderr, "Test Unit Ready failed\n");
5800			goto ratecontrol_bailout;
5801		}
5802	}
5803	if ((change_settings || send_tur) && !quiet &&
5804	    (ccb->cts.transport == XPORT_ATA ||
5805	     ccb->cts.transport == XPORT_SATA || send_tur)) {
5806		fprintf(stdout, "New parameters:\n");
5807		retval = get_print_cts(device, user_settings, 0, NULL);
5808	}
5809
5810ratecontrol_bailout:
5811	cam_freeccb(ccb);
5812	return(retval);
5813}
5814
5815static int
5816scsiformat(struct cam_device *device, int argc, char **argv,
5817	   char *combinedopt, int task_attr, int retry_count, int timeout)
5818{
5819	union ccb *ccb;
5820	int c;
5821	int ycount = 0, quiet = 0;
5822	int error = 0, retval = 0;
5823	int use_timeout = 10800 * 1000;
5824	int immediate = 1;
5825	struct format_defect_list_header fh;
5826	u_int8_t *data_ptr = NULL;
5827	u_int32_t dxfer_len = 0;
5828	u_int8_t byte2 = 0;
5829	int num_warnings = 0;
5830	int reportonly = 0;
5831
5832	ccb = cam_getccb(device);
5833
5834	if (ccb == NULL) {
5835		warnx("scsiformat: error allocating ccb");
5836		return(1);
5837	}
5838
5839	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
5840
5841	while ((c = getopt(argc, argv, combinedopt)) != -1) {
5842		switch(c) {
5843		case 'q':
5844			quiet++;
5845			break;
5846		case 'r':
5847			reportonly = 1;
5848			break;
5849		case 'w':
5850			immediate = 0;
5851			break;
5852		case 'y':
5853			ycount++;
5854			break;
5855		}
5856	}
5857
5858	if (reportonly)
5859		goto doreport;
5860
5861	if (quiet == 0) {
5862		fprintf(stdout, "You are about to REMOVE ALL DATA from the "
5863			"following device:\n");
5864
5865		error = scsidoinquiry(device, argc, argv, combinedopt,
5866				      task_attr, retry_count, timeout);
5867
5868		if (error != 0) {
5869			warnx("scsiformat: error sending inquiry");
5870			goto scsiformat_bailout;
5871		}
5872	}
5873
5874	if (ycount == 0) {
5875		if (!get_confirmation()) {
5876			error = 1;
5877			goto scsiformat_bailout;
5878		}
5879	}
5880
5881	if (timeout != 0)
5882		use_timeout = timeout;
5883
5884	if (quiet == 0) {
5885		fprintf(stdout, "Current format timeout is %d seconds\n",
5886			use_timeout / 1000);
5887	}
5888
5889	/*
5890	 * If the user hasn't disabled questions and didn't specify a
5891	 * timeout on the command line, ask them if they want the current
5892	 * timeout.
5893	 */
5894	if ((ycount == 0)
5895	 && (timeout == 0)) {
5896		char str[1024];
5897		int new_timeout = 0;
5898
5899		fprintf(stdout, "Enter new timeout in seconds or press\n"
5900			"return to keep the current timeout [%d] ",
5901			use_timeout / 1000);
5902
5903		if (fgets(str, sizeof(str), stdin) != NULL) {
5904			if (str[0] != '\0')
5905				new_timeout = atoi(str);
5906		}
5907
5908		if (new_timeout != 0) {
5909			use_timeout = new_timeout * 1000;
5910			fprintf(stdout, "Using new timeout value %d\n",
5911				use_timeout / 1000);
5912		}
5913	}
5914
5915	/*
5916	 * Keep this outside the if block below to silence any unused
5917	 * variable warnings.
5918	 */
5919	bzero(&fh, sizeof(fh));
5920
5921	/*
5922	 * If we're in immediate mode, we've got to include the format
5923	 * header
5924	 */
5925	if (immediate != 0) {
5926		fh.byte2 = FU_DLH_IMMED;
5927		data_ptr = (u_int8_t *)&fh;
5928		dxfer_len = sizeof(fh);
5929		byte2 = FU_FMT_DATA;
5930	} else if (quiet == 0) {
5931		fprintf(stdout, "Formatting...");
5932		fflush(stdout);
5933	}
5934
5935	scsi_format_unit(&ccb->csio,
5936			 /* retries */ retry_count,
5937			 /* cbfcnp */ NULL,
5938			 /* tag_action */ task_attr,
5939			 /* byte2 */ byte2,
5940			 /* ileave */ 0,
5941			 /* data_ptr */ data_ptr,
5942			 /* dxfer_len */ dxfer_len,
5943			 /* sense_len */ SSD_FULL_SIZE,
5944			 /* timeout */ use_timeout);
5945
5946	/* Disable freezing the device queue */
5947	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
5948
5949	if (arglist & CAM_ARG_ERR_RECOVER)
5950		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
5951
5952	if (((retval = cam_send_ccb(device, ccb)) < 0)
5953	 || ((immediate == 0)
5954	   && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP))) {
5955		const char errstr[] = "error sending format command";
5956
5957		if (retval < 0)
5958			warn(errstr);
5959		else
5960			warnx(errstr);
5961
5962		if (arglist & CAM_ARG_VERBOSE) {
5963			cam_error_print(device, ccb, CAM_ESF_ALL,
5964					CAM_EPF_ALL, stderr);
5965		}
5966		error = 1;
5967		goto scsiformat_bailout;
5968	}
5969
5970	/*
5971	 * If we ran in non-immediate mode, we already checked for errors
5972	 * above and printed out any necessary information.  If we're in
5973	 * immediate mode, we need to loop through and get status
5974	 * information periodically.
5975	 */
5976	if (immediate == 0) {
5977		if (quiet == 0) {
5978			fprintf(stdout, "Format Complete\n");
5979		}
5980		goto scsiformat_bailout;
5981	}
5982
5983doreport:
5984	do {
5985		cam_status status;
5986
5987		CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
5988
5989		/*
5990		 * There's really no need to do error recovery or
5991		 * retries here, since we're just going to sit in a
5992		 * loop and wait for the device to finish formatting.
5993		 */
5994		scsi_test_unit_ready(&ccb->csio,
5995				     /* retries */ 0,
5996				     /* cbfcnp */ NULL,
5997				     /* tag_action */ task_attr,
5998				     /* sense_len */ SSD_FULL_SIZE,
5999				     /* timeout */ 5000);
6000
6001		/* Disable freezing the device queue */
6002		ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
6003
6004		retval = cam_send_ccb(device, ccb);
6005
6006		/*
6007		 * If we get an error from the ioctl, bail out.  SCSI
6008		 * errors are expected.
6009		 */
6010		if (retval < 0) {
6011			warn("error sending CAMIOCOMMAND ioctl");
6012			if (arglist & CAM_ARG_VERBOSE) {
6013				cam_error_print(device, ccb, CAM_ESF_ALL,
6014						CAM_EPF_ALL, stderr);
6015			}
6016			error = 1;
6017			goto scsiformat_bailout;
6018		}
6019
6020		status = ccb->ccb_h.status & CAM_STATUS_MASK;
6021
6022		if ((status != CAM_REQ_CMP)
6023		 && (status == CAM_SCSI_STATUS_ERROR)
6024		 && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) {
6025			struct scsi_sense_data *sense;
6026			int error_code, sense_key, asc, ascq;
6027
6028			sense = &ccb->csio.sense_data;
6029			scsi_extract_sense_len(sense, ccb->csio.sense_len -
6030			    ccb->csio.sense_resid, &error_code, &sense_key,
6031			    &asc, &ascq, /*show_errors*/ 1);
6032
6033			/*
6034			 * According to the SCSI-2 and SCSI-3 specs, a
6035			 * drive that is in the middle of a format should
6036			 * return NOT READY with an ASC of "logical unit
6037			 * not ready, format in progress".  The sense key
6038			 * specific bytes will then be a progress indicator.
6039			 */
6040			if ((sense_key == SSD_KEY_NOT_READY)
6041			 && (asc == 0x04) && (ascq == 0x04)) {
6042				uint8_t sks[3];
6043
6044				if ((scsi_get_sks(sense, ccb->csio.sense_len -
6045				     ccb->csio.sense_resid, sks) == 0)
6046				 && (quiet == 0)) {
6047					uint32_t val;
6048					u_int64_t percentage;
6049
6050					val = scsi_2btoul(&sks[1]);
6051					percentage = 10000ull * val;
6052
6053					fprintf(stdout,
6054						"\rFormatting:  %ju.%02u %% "
6055						"(%u/%d) done",
6056						(uintmax_t)(percentage /
6057						(0x10000 * 100)),
6058						(unsigned)((percentage /
6059						0x10000) % 100),
6060						val, 0x10000);
6061					fflush(stdout);
6062				} else if ((quiet == 0)
6063					&& (++num_warnings <= 1)) {
6064					warnx("Unexpected SCSI Sense Key "
6065					      "Specific value returned "
6066					      "during format:");
6067					scsi_sense_print(device, &ccb->csio,
6068							 stderr);
6069					warnx("Unable to print status "
6070					      "information, but format will "
6071					      "proceed.");
6072					warnx("will exit when format is "
6073					      "complete");
6074				}
6075				sleep(1);
6076			} else {
6077				warnx("Unexpected SCSI error during format");
6078				cam_error_print(device, ccb, CAM_ESF_ALL,
6079						CAM_EPF_ALL, stderr);
6080				error = 1;
6081				goto scsiformat_bailout;
6082			}
6083
6084		} else if (status != CAM_REQ_CMP) {
6085			warnx("Unexpected CAM status %#x", status);
6086			if (arglist & CAM_ARG_VERBOSE)
6087				cam_error_print(device, ccb, CAM_ESF_ALL,
6088						CAM_EPF_ALL, stderr);
6089			error = 1;
6090			goto scsiformat_bailout;
6091		}
6092
6093	} while((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP);
6094
6095	if (quiet == 0)
6096		fprintf(stdout, "\nFormat Complete\n");
6097
6098scsiformat_bailout:
6099
6100	cam_freeccb(ccb);
6101
6102	return(error);
6103}
6104
6105static int
6106scsisanitize(struct cam_device *device, int argc, char **argv,
6107	     char *combinedopt, int task_attr, int retry_count, int timeout)
6108{
6109	union ccb *ccb;
6110	u_int8_t action = 0;
6111	int c;
6112	int ycount = 0, quiet = 0;
6113	int error = 0, retval = 0;
6114	int use_timeout = 10800 * 1000;
6115	int immediate = 1;
6116	int invert = 0;
6117	int passes = 0;
6118	int ause = 0;
6119	int fd = -1;
6120	const char *pattern = NULL;
6121	u_int8_t *data_ptr = NULL;
6122	u_int32_t dxfer_len = 0;
6123	u_int8_t byte2 = 0;
6124	int num_warnings = 0;
6125	int reportonly = 0;
6126
6127	ccb = cam_getccb(device);
6128
6129	if (ccb == NULL) {
6130		warnx("scsisanitize: error allocating ccb");
6131		return(1);
6132	}
6133
6134	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
6135
6136	while ((c = getopt(argc, argv, combinedopt)) != -1) {
6137		switch(c) {
6138		case 'a':
6139			if (strcasecmp(optarg, "overwrite") == 0)
6140				action = SSZ_SERVICE_ACTION_OVERWRITE;
6141			else if (strcasecmp(optarg, "block") == 0)
6142				action = SSZ_SERVICE_ACTION_BLOCK_ERASE;
6143			else if (strcasecmp(optarg, "crypto") == 0)
6144				action = SSZ_SERVICE_ACTION_CRYPTO_ERASE;
6145			else if (strcasecmp(optarg, "exitfailure") == 0)
6146				action = SSZ_SERVICE_ACTION_EXIT_MODE_FAILURE;
6147			else {
6148				warnx("invalid service operation \"%s\"",
6149				      optarg);
6150				error = 1;
6151				goto scsisanitize_bailout;
6152			}
6153			break;
6154		case 'c':
6155			passes = strtol(optarg, NULL, 0);
6156			if (passes < 1 || passes > 31) {
6157				warnx("invalid passes value %d", passes);
6158				error = 1;
6159				goto scsisanitize_bailout;
6160			}
6161			break;
6162		case 'I':
6163			invert = 1;
6164			break;
6165		case 'P':
6166			pattern = optarg;
6167			break;
6168		case 'q':
6169			quiet++;
6170			break;
6171		case 'U':
6172			ause = 1;
6173			break;
6174		case 'r':
6175			reportonly = 1;
6176			break;
6177		case 'w':
6178			immediate = 0;
6179			break;
6180		case 'y':
6181			ycount++;
6182			break;
6183		}
6184	}
6185
6186	if (reportonly)
6187		goto doreport;
6188
6189	if (action == 0) {
6190		warnx("an action is required");
6191		error = 1;
6192		goto scsisanitize_bailout;
6193	} else if (action == SSZ_SERVICE_ACTION_OVERWRITE) {
6194		struct scsi_sanitize_parameter_list *pl;
6195		struct stat sb;
6196		ssize_t sz, amt;
6197
6198		if (pattern == NULL) {
6199			warnx("overwrite action requires -P argument");
6200			error = 1;
6201			goto scsisanitize_bailout;
6202		}
6203		fd = open(pattern, O_RDONLY);
6204		if (fd < 0) {
6205			warn("cannot open pattern file %s", pattern);
6206			error = 1;
6207			goto scsisanitize_bailout;
6208		}
6209		if (fstat(fd, &sb) < 0) {
6210			warn("cannot stat pattern file %s", pattern);
6211			error = 1;
6212			goto scsisanitize_bailout;
6213		}
6214		sz = sb.st_size;
6215		if (sz > SSZPL_MAX_PATTERN_LENGTH) {
6216			warnx("pattern file size exceeds maximum value %d",
6217			      SSZPL_MAX_PATTERN_LENGTH);
6218			error = 1;
6219			goto scsisanitize_bailout;
6220		}
6221		dxfer_len = sizeof(*pl) + sz;
6222		data_ptr = calloc(1, dxfer_len);
6223		if (data_ptr == NULL) {
6224			warnx("cannot allocate parameter list buffer");
6225			error = 1;
6226			goto scsisanitize_bailout;
6227		}
6228
6229		amt = read(fd, data_ptr + sizeof(*pl), sz);
6230		if (amt < 0) {
6231			warn("cannot read pattern file");
6232			error = 1;
6233			goto scsisanitize_bailout;
6234		} else if (amt != sz) {
6235			warnx("short pattern file read");
6236			error = 1;
6237			goto scsisanitize_bailout;
6238		}
6239
6240		pl = (struct scsi_sanitize_parameter_list *)data_ptr;
6241		if (passes == 0)
6242			pl->byte1 = 1;
6243		else
6244			pl->byte1 = passes;
6245		if (invert != 0)
6246			pl->byte1 |= SSZPL_INVERT;
6247		scsi_ulto2b(sz, pl->length);
6248	} else {
6249		const char *arg;
6250
6251		if (passes != 0)
6252			arg = "-c";
6253		else if (invert != 0)
6254			arg = "-I";
6255		else if (pattern != NULL)
6256			arg = "-P";
6257		else
6258			arg = NULL;
6259		if (arg != NULL) {
6260			warnx("%s argument only valid with overwrite "
6261			      "operation", arg);
6262			error = 1;
6263			goto scsisanitize_bailout;
6264		}
6265	}
6266
6267	if (quiet == 0) {
6268		fprintf(stdout, "You are about to REMOVE ALL DATA from the "
6269			"following device:\n");
6270
6271		error = scsidoinquiry(device, argc, argv, combinedopt,
6272				      task_attr, retry_count, timeout);
6273
6274		if (error != 0) {
6275			warnx("scsisanitize: error sending inquiry");
6276			goto scsisanitize_bailout;
6277		}
6278	}
6279
6280	if (ycount == 0) {
6281		if (!get_confirmation()) {
6282			error = 1;
6283			goto scsisanitize_bailout;
6284		}
6285	}
6286
6287	if (timeout != 0)
6288		use_timeout = timeout;
6289
6290	if (quiet == 0) {
6291		fprintf(stdout, "Current sanitize timeout is %d seconds\n",
6292			use_timeout / 1000);
6293	}
6294
6295	/*
6296	 * If the user hasn't disabled questions and didn't specify a
6297	 * timeout on the command line, ask them if they want the current
6298	 * timeout.
6299	 */
6300	if ((ycount == 0)
6301	 && (timeout == 0)) {
6302		char str[1024];
6303		int new_timeout = 0;
6304
6305		fprintf(stdout, "Enter new timeout in seconds or press\n"
6306			"return to keep the current timeout [%d] ",
6307			use_timeout / 1000);
6308
6309		if (fgets(str, sizeof(str), stdin) != NULL) {
6310			if (str[0] != '\0')
6311				new_timeout = atoi(str);
6312		}
6313
6314		if (new_timeout != 0) {
6315			use_timeout = new_timeout * 1000;
6316			fprintf(stdout, "Using new timeout value %d\n",
6317				use_timeout / 1000);
6318		}
6319	}
6320
6321	byte2 = action;
6322	if (ause != 0)
6323		byte2 |= SSZ_UNRESTRICTED_EXIT;
6324	if (immediate != 0)
6325		byte2 |= SSZ_IMMED;
6326
6327	scsi_sanitize(&ccb->csio,
6328		      /* retries */ retry_count,
6329		      /* cbfcnp */ NULL,
6330		      /* tag_action */ task_attr,
6331		      /* byte2 */ byte2,
6332		      /* control */ 0,
6333		      /* data_ptr */ data_ptr,
6334		      /* dxfer_len */ dxfer_len,
6335		      /* sense_len */ SSD_FULL_SIZE,
6336		      /* timeout */ use_timeout);
6337
6338	/* Disable freezing the device queue */
6339	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
6340
6341	if (arglist & CAM_ARG_ERR_RECOVER)
6342		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
6343
6344	if (cam_send_ccb(device, ccb) < 0) {
6345		warn("error sending sanitize command");
6346		error = 1;
6347		goto scsisanitize_bailout;
6348	}
6349
6350	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
6351		struct scsi_sense_data *sense;
6352		int error_code, sense_key, asc, ascq;
6353
6354		if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
6355		    CAM_SCSI_STATUS_ERROR) {
6356			sense = &ccb->csio.sense_data;
6357			scsi_extract_sense_len(sense, ccb->csio.sense_len -
6358			    ccb->csio.sense_resid, &error_code, &sense_key,
6359			    &asc, &ascq, /*show_errors*/ 1);
6360
6361			if (sense_key == SSD_KEY_ILLEGAL_REQUEST &&
6362			    asc == 0x20 && ascq == 0x00)
6363				warnx("sanitize is not supported by "
6364				      "this device");
6365			else
6366				warnx("error sanitizing this device");
6367		} else
6368			warnx("error sanitizing this device");
6369
6370		if (arglist & CAM_ARG_VERBOSE) {
6371			cam_error_print(device, ccb, CAM_ESF_ALL,
6372					CAM_EPF_ALL, stderr);
6373		}
6374		error = 1;
6375		goto scsisanitize_bailout;
6376	}
6377
6378	/*
6379	 * If we ran in non-immediate mode, we already checked for errors
6380	 * above and printed out any necessary information.  If we're in
6381	 * immediate mode, we need to loop through and get status
6382	 * information periodically.
6383	 */
6384	if (immediate == 0) {
6385		if (quiet == 0) {
6386			fprintf(stdout, "Sanitize Complete\n");
6387		}
6388		goto scsisanitize_bailout;
6389	}
6390
6391doreport:
6392	do {
6393		cam_status status;
6394
6395		CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
6396
6397		/*
6398		 * There's really no need to do error recovery or
6399		 * retries here, since we're just going to sit in a
6400		 * loop and wait for the device to finish sanitizing.
6401		 */
6402		scsi_test_unit_ready(&ccb->csio,
6403				     /* retries */ 0,
6404				     /* cbfcnp */ NULL,
6405				     /* tag_action */ task_attr,
6406				     /* sense_len */ SSD_FULL_SIZE,
6407				     /* timeout */ 5000);
6408
6409		/* Disable freezing the device queue */
6410		ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
6411
6412		retval = cam_send_ccb(device, ccb);
6413
6414		/*
6415		 * If we get an error from the ioctl, bail out.  SCSI
6416		 * errors are expected.
6417		 */
6418		if (retval < 0) {
6419			warn("error sending CAMIOCOMMAND ioctl");
6420			if (arglist & CAM_ARG_VERBOSE) {
6421				cam_error_print(device, ccb, CAM_ESF_ALL,
6422						CAM_EPF_ALL, stderr);
6423			}
6424			error = 1;
6425			goto scsisanitize_bailout;
6426		}
6427
6428		status = ccb->ccb_h.status & CAM_STATUS_MASK;
6429
6430		if ((status != CAM_REQ_CMP)
6431		 && (status == CAM_SCSI_STATUS_ERROR)
6432		 && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) {
6433			struct scsi_sense_data *sense;
6434			int error_code, sense_key, asc, ascq;
6435
6436			sense = &ccb->csio.sense_data;
6437			scsi_extract_sense_len(sense, ccb->csio.sense_len -
6438			    ccb->csio.sense_resid, &error_code, &sense_key,
6439			    &asc, &ascq, /*show_errors*/ 1);
6440
6441			/*
6442			 * According to the SCSI-3 spec, a drive that is in the
6443			 * middle of a sanitize should return NOT READY with an
6444			 * ASC of "logical unit not ready, sanitize in
6445			 * progress". The sense key specific bytes will then
6446			 * be a progress indicator.
6447			 */
6448			if ((sense_key == SSD_KEY_NOT_READY)
6449			 && (asc == 0x04) && (ascq == 0x1b)) {
6450				uint8_t sks[3];
6451
6452				if ((scsi_get_sks(sense, ccb->csio.sense_len -
6453				     ccb->csio.sense_resid, sks) == 0)
6454				 && (quiet == 0)) {
6455					int val;
6456					u_int64_t percentage;
6457
6458					val = scsi_2btoul(&sks[1]);
6459					percentage = 10000 * val;
6460
6461					fprintf(stdout,
6462						"\rSanitizing:  %ju.%02u %% "
6463						"(%d/%d) done",
6464						(uintmax_t)(percentage /
6465						(0x10000 * 100)),
6466						(unsigned)((percentage /
6467						0x10000) % 100),
6468						val, 0x10000);
6469					fflush(stdout);
6470				} else if ((quiet == 0)
6471					&& (++num_warnings <= 1)) {
6472					warnx("Unexpected SCSI Sense Key "
6473					      "Specific value returned "
6474					      "during sanitize:");
6475					scsi_sense_print(device, &ccb->csio,
6476							 stderr);
6477					warnx("Unable to print status "
6478					      "information, but sanitze will "
6479					      "proceed.");
6480					warnx("will exit when sanitize is "
6481					      "complete");
6482				}
6483				sleep(1);
6484			} else {
6485				warnx("Unexpected SCSI error during sanitize");
6486				cam_error_print(device, ccb, CAM_ESF_ALL,
6487						CAM_EPF_ALL, stderr);
6488				error = 1;
6489				goto scsisanitize_bailout;
6490			}
6491
6492		} else if (status != CAM_REQ_CMP) {
6493			warnx("Unexpected CAM status %#x", status);
6494			if (arglist & CAM_ARG_VERBOSE)
6495				cam_error_print(device, ccb, CAM_ESF_ALL,
6496						CAM_EPF_ALL, stderr);
6497			error = 1;
6498			goto scsisanitize_bailout;
6499		}
6500	} while((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP);
6501
6502	if (quiet == 0)
6503		fprintf(stdout, "\nSanitize Complete\n");
6504
6505scsisanitize_bailout:
6506	if (fd >= 0)
6507		close(fd);
6508	if (data_ptr != NULL)
6509		free(data_ptr);
6510	cam_freeccb(ccb);
6511
6512	return(error);
6513}
6514
6515static int
6516scsireportluns(struct cam_device *device, int argc, char **argv,
6517	       char *combinedopt, int task_attr, int retry_count, int timeout)
6518{
6519	union ccb *ccb;
6520	int c, countonly, lunsonly;
6521	struct scsi_report_luns_data *lundata;
6522	int alloc_len;
6523	uint8_t report_type;
6524	uint32_t list_len, i, j;
6525	int retval;
6526
6527	retval = 0;
6528	lundata = NULL;
6529	report_type = RPL_REPORT_DEFAULT;
6530	ccb = cam_getccb(device);
6531
6532	if (ccb == NULL) {
6533		warnx("%s: error allocating ccb", __func__);
6534		return (1);
6535	}
6536
6537	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
6538
6539	countonly = 0;
6540	lunsonly = 0;
6541
6542	while ((c = getopt(argc, argv, combinedopt)) != -1) {
6543		switch (c) {
6544		case 'c':
6545			countonly++;
6546			break;
6547		case 'l':
6548			lunsonly++;
6549			break;
6550		case 'r':
6551			if (strcasecmp(optarg, "default") == 0)
6552				report_type = RPL_REPORT_DEFAULT;
6553			else if (strcasecmp(optarg, "wellknown") == 0)
6554				report_type = RPL_REPORT_WELLKNOWN;
6555			else if (strcasecmp(optarg, "all") == 0)
6556				report_type = RPL_REPORT_ALL;
6557			else {
6558				warnx("%s: invalid report type \"%s\"",
6559				      __func__, optarg);
6560				retval = 1;
6561				goto bailout;
6562			}
6563			break;
6564		default:
6565			break;
6566		}
6567	}
6568
6569	if ((countonly != 0)
6570	 && (lunsonly != 0)) {
6571		warnx("%s: you can only specify one of -c or -l", __func__);
6572		retval = 1;
6573		goto bailout;
6574	}
6575	/*
6576	 * According to SPC-4, the allocation length must be at least 16
6577	 * bytes -- enough for the header and one LUN.
6578	 */
6579	alloc_len = sizeof(*lundata) + 8;
6580
6581retry:
6582
6583	lundata = malloc(alloc_len);
6584
6585	if (lundata == NULL) {
6586		warn("%s: error mallocing %d bytes", __func__, alloc_len);
6587		retval = 1;
6588		goto bailout;
6589	}
6590
6591	scsi_report_luns(&ccb->csio,
6592			 /*retries*/ retry_count,
6593			 /*cbfcnp*/ NULL,
6594			 /*tag_action*/ task_attr,
6595			 /*select_report*/ report_type,
6596			 /*rpl_buf*/ lundata,
6597			 /*alloc_len*/ alloc_len,
6598			 /*sense_len*/ SSD_FULL_SIZE,
6599			 /*timeout*/ timeout ? timeout : 5000);
6600
6601	/* Disable freezing the device queue */
6602	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
6603
6604	if (arglist & CAM_ARG_ERR_RECOVER)
6605		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
6606
6607	if (cam_send_ccb(device, ccb) < 0) {
6608		warn("error sending REPORT LUNS command");
6609
6610		if (arglist & CAM_ARG_VERBOSE)
6611			cam_error_print(device, ccb, CAM_ESF_ALL,
6612					CAM_EPF_ALL, stderr);
6613
6614		retval = 1;
6615		goto bailout;
6616	}
6617
6618	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
6619		cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
6620		retval = 1;
6621		goto bailout;
6622	}
6623
6624
6625	list_len = scsi_4btoul(lundata->length);
6626
6627	/*
6628	 * If we need to list the LUNs, and our allocation
6629	 * length was too short, reallocate and retry.
6630	 */
6631	if ((countonly == 0)
6632	 && (list_len > (alloc_len - sizeof(*lundata)))) {
6633		alloc_len = list_len + sizeof(*lundata);
6634		free(lundata);
6635		goto retry;
6636	}
6637
6638	if (lunsonly == 0)
6639		fprintf(stdout, "%u LUN%s found\n", list_len / 8,
6640			((list_len / 8) > 1) ? "s" : "");
6641
6642	if (countonly != 0)
6643		goto bailout;
6644
6645	for (i = 0; i < (list_len / 8); i++) {
6646		int no_more;
6647
6648		no_more = 0;
6649		for (j = 0; j < sizeof(lundata->luns[i].lundata); j += 2) {
6650			if (j != 0)
6651				fprintf(stdout, ",");
6652			switch (lundata->luns[i].lundata[j] &
6653				RPL_LUNDATA_ATYP_MASK) {
6654			case RPL_LUNDATA_ATYP_PERIPH:
6655				if ((lundata->luns[i].lundata[j] &
6656				    RPL_LUNDATA_PERIPH_BUS_MASK) != 0)
6657					fprintf(stdout, "%d:",
6658						lundata->luns[i].lundata[j] &
6659						RPL_LUNDATA_PERIPH_BUS_MASK);
6660				else if ((j == 0)
6661				      && ((lundata->luns[i].lundata[j+2] &
6662					  RPL_LUNDATA_PERIPH_BUS_MASK) == 0))
6663					no_more = 1;
6664
6665				fprintf(stdout, "%d",
6666					lundata->luns[i].lundata[j+1]);
6667				break;
6668			case RPL_LUNDATA_ATYP_FLAT: {
6669				uint8_t tmplun[2];
6670				tmplun[0] = lundata->luns[i].lundata[j] &
6671					RPL_LUNDATA_FLAT_LUN_MASK;
6672				tmplun[1] = lundata->luns[i].lundata[j+1];
6673
6674				fprintf(stdout, "%d", scsi_2btoul(tmplun));
6675				no_more = 1;
6676				break;
6677			}
6678			case RPL_LUNDATA_ATYP_LUN:
6679				fprintf(stdout, "%d:%d:%d",
6680					(lundata->luns[i].lundata[j+1] &
6681					RPL_LUNDATA_LUN_BUS_MASK) >> 5,
6682					lundata->luns[i].lundata[j] &
6683					RPL_LUNDATA_LUN_TARG_MASK,
6684					lundata->luns[i].lundata[j+1] &
6685					RPL_LUNDATA_LUN_LUN_MASK);
6686				break;
6687			case RPL_LUNDATA_ATYP_EXTLUN: {
6688				int field_len_code, eam_code;
6689
6690				eam_code = lundata->luns[i].lundata[j] &
6691					RPL_LUNDATA_EXT_EAM_MASK;
6692				field_len_code = (lundata->luns[i].lundata[j] &
6693					RPL_LUNDATA_EXT_LEN_MASK) >> 4;
6694
6695				if ((eam_code == RPL_LUNDATA_EXT_EAM_WK)
6696				 && (field_len_code == 0x00)) {
6697					fprintf(stdout, "%d",
6698						lundata->luns[i].lundata[j+1]);
6699				} else if ((eam_code ==
6700					    RPL_LUNDATA_EXT_EAM_NOT_SPEC)
6701					&& (field_len_code == 0x03)) {
6702					uint8_t tmp_lun[8];
6703
6704					/*
6705					 * This format takes up all 8 bytes.
6706					 * If we aren't starting at offset 0,
6707					 * that's a bug.
6708					 */
6709					if (j != 0) {
6710						fprintf(stdout, "Invalid "
6711							"offset %d for "
6712							"Extended LUN not "
6713							"specified format", j);
6714						no_more = 1;
6715						break;
6716					}
6717					bzero(tmp_lun, sizeof(tmp_lun));
6718					bcopy(&lundata->luns[i].lundata[j+1],
6719					      &tmp_lun[1], sizeof(tmp_lun) - 1);
6720					fprintf(stdout, "%#jx",
6721					       (intmax_t)scsi_8btou64(tmp_lun));
6722					no_more = 1;
6723				} else {
6724					fprintf(stderr, "Unknown Extended LUN"
6725						"Address method %#x, length "
6726						"code %#x", eam_code,
6727						field_len_code);
6728					no_more = 1;
6729				}
6730				break;
6731			}
6732			default:
6733				fprintf(stderr, "Unknown LUN address method "
6734					"%#x\n", lundata->luns[i].lundata[0] &
6735					RPL_LUNDATA_ATYP_MASK);
6736				break;
6737			}
6738			/*
6739			 * For the flat addressing method, there are no
6740			 * other levels after it.
6741			 */
6742			if (no_more != 0)
6743				break;
6744		}
6745		fprintf(stdout, "\n");
6746	}
6747
6748bailout:
6749
6750	cam_freeccb(ccb);
6751
6752	free(lundata);
6753
6754	return (retval);
6755}
6756
6757static int
6758scsireadcapacity(struct cam_device *device, int argc, char **argv,
6759		 char *combinedopt, int task_attr, int retry_count, int timeout)
6760{
6761	union ccb *ccb;
6762	int blocksizeonly, humanize, numblocks, quiet, sizeonly, baseten;
6763	struct scsi_read_capacity_data rcap;
6764	struct scsi_read_capacity_data_long rcaplong;
6765	uint64_t maxsector;
6766	uint32_t block_len;
6767	int retval;
6768	int c;
6769
6770	blocksizeonly = 0;
6771	humanize = 0;
6772	numblocks = 0;
6773	quiet = 0;
6774	sizeonly = 0;
6775	baseten = 0;
6776	retval = 0;
6777
6778	ccb = cam_getccb(device);
6779
6780	if (ccb == NULL) {
6781		warnx("%s: error allocating ccb", __func__);
6782		return (1);
6783	}
6784
6785	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
6786
6787	while ((c = getopt(argc, argv, combinedopt)) != -1) {
6788		switch (c) {
6789		case 'b':
6790			blocksizeonly++;
6791			break;
6792		case 'h':
6793			humanize++;
6794			baseten = 0;
6795			break;
6796		case 'H':
6797			humanize++;
6798			baseten++;
6799			break;
6800		case 'N':
6801			numblocks++;
6802			break;
6803		case 'q':
6804			quiet++;
6805			break;
6806		case 's':
6807			sizeonly++;
6808			break;
6809		default:
6810			break;
6811		}
6812	}
6813
6814	if ((blocksizeonly != 0)
6815	 && (numblocks != 0)) {
6816		warnx("%s: you can only specify one of -b or -N", __func__);
6817		retval = 1;
6818		goto bailout;
6819	}
6820
6821	if ((blocksizeonly != 0)
6822	 && (sizeonly != 0)) {
6823		warnx("%s: you can only specify one of -b or -s", __func__);
6824		retval = 1;
6825		goto bailout;
6826	}
6827
6828	if ((humanize != 0)
6829	 && (quiet != 0)) {
6830		warnx("%s: you can only specify one of -h/-H or -q", __func__);
6831		retval = 1;
6832		goto bailout;
6833	}
6834
6835	if ((humanize != 0)
6836	 && (blocksizeonly != 0)) {
6837		warnx("%s: you can only specify one of -h/-H or -b", __func__);
6838		retval = 1;
6839		goto bailout;
6840	}
6841
6842	scsi_read_capacity(&ccb->csio,
6843			   /*retries*/ retry_count,
6844			   /*cbfcnp*/ NULL,
6845			   /*tag_action*/ task_attr,
6846			   &rcap,
6847			   SSD_FULL_SIZE,
6848			   /*timeout*/ timeout ? timeout : 5000);
6849
6850	/* Disable freezing the device queue */
6851	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
6852
6853	if (arglist & CAM_ARG_ERR_RECOVER)
6854		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
6855
6856	if (cam_send_ccb(device, ccb) < 0) {
6857		warn("error sending READ CAPACITY command");
6858
6859		if (arglist & CAM_ARG_VERBOSE)
6860			cam_error_print(device, ccb, CAM_ESF_ALL,
6861					CAM_EPF_ALL, stderr);
6862
6863		retval = 1;
6864		goto bailout;
6865	}
6866
6867	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
6868		cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
6869		retval = 1;
6870		goto bailout;
6871	}
6872
6873	maxsector = scsi_4btoul(rcap.addr);
6874	block_len = scsi_4btoul(rcap.length);
6875
6876	/*
6877	 * A last block of 2^32-1 means that the true capacity is over 2TB,
6878	 * and we need to issue the long READ CAPACITY to get the real
6879	 * capacity.  Otherwise, we're all set.
6880	 */
6881	if (maxsector != 0xffffffff)
6882		goto do_print;
6883
6884	scsi_read_capacity_16(&ccb->csio,
6885			      /*retries*/ retry_count,
6886			      /*cbfcnp*/ NULL,
6887			      /*tag_action*/ task_attr,
6888			      /*lba*/ 0,
6889			      /*reladdr*/ 0,
6890			      /*pmi*/ 0,
6891			      /*rcap_buf*/ (uint8_t *)&rcaplong,
6892			      /*rcap_buf_len*/ sizeof(rcaplong),
6893			      /*sense_len*/ SSD_FULL_SIZE,
6894			      /*timeout*/ timeout ? timeout : 5000);
6895
6896	/* Disable freezing the device queue */
6897	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
6898
6899	if (arglist & CAM_ARG_ERR_RECOVER)
6900		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
6901
6902	if (cam_send_ccb(device, ccb) < 0) {
6903		warn("error sending READ CAPACITY (16) command");
6904
6905		if (arglist & CAM_ARG_VERBOSE)
6906			cam_error_print(device, ccb, CAM_ESF_ALL,
6907					CAM_EPF_ALL, stderr);
6908
6909		retval = 1;
6910		goto bailout;
6911	}
6912
6913	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
6914		cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
6915		retval = 1;
6916		goto bailout;
6917	}
6918
6919	maxsector = scsi_8btou64(rcaplong.addr);
6920	block_len = scsi_4btoul(rcaplong.length);
6921
6922do_print:
6923	if (blocksizeonly == 0) {
6924		/*
6925		 * Humanize implies !quiet, and also implies numblocks.
6926		 */
6927		if (humanize != 0) {
6928			char tmpstr[6];
6929			int64_t tmpbytes;
6930			int ret;
6931
6932			tmpbytes = (maxsector + 1) * block_len;
6933			ret = humanize_number(tmpstr, sizeof(tmpstr),
6934					      tmpbytes, "", HN_AUTOSCALE,
6935					      HN_B | HN_DECIMAL |
6936					      ((baseten != 0) ?
6937					      HN_DIVISOR_1000 : 0));
6938			if (ret == -1) {
6939				warnx("%s: humanize_number failed!", __func__);
6940				retval = 1;
6941				goto bailout;
6942			}
6943			fprintf(stdout, "Device Size: %s%s", tmpstr,
6944				(sizeonly == 0) ?  ", " : "\n");
6945		} else if (numblocks != 0) {
6946			fprintf(stdout, "%s%ju%s", (quiet == 0) ?
6947				"Blocks: " : "", (uintmax_t)maxsector + 1,
6948				(sizeonly == 0) ? ", " : "\n");
6949		} else {
6950			fprintf(stdout, "%s%ju%s", (quiet == 0) ?
6951				"Last Block: " : "", (uintmax_t)maxsector,
6952				(sizeonly == 0) ? ", " : "\n");
6953		}
6954	}
6955	if (sizeonly == 0)
6956		fprintf(stdout, "%s%u%s\n", (quiet == 0) ?
6957			"Block Length: " : "", block_len, (quiet == 0) ?
6958			" bytes" : "");
6959bailout:
6960	cam_freeccb(ccb);
6961
6962	return (retval);
6963}
6964
6965static int
6966smpcmd(struct cam_device *device, int argc, char **argv, char *combinedopt,
6967       int retry_count, int timeout)
6968{
6969	int c, error = 0;
6970	union ccb *ccb;
6971	uint8_t *smp_request = NULL, *smp_response = NULL;
6972	int request_size = 0, response_size = 0;
6973	int fd_request = 0, fd_response = 0;
6974	char *datastr = NULL;
6975	struct get_hook hook;
6976	int retval;
6977	int flags = 0;
6978
6979	/*
6980	 * Note that at the moment we don't support sending SMP CCBs to
6981	 * devices that aren't probed by CAM.
6982	 */
6983	ccb = cam_getccb(device);
6984	if (ccb == NULL) {
6985		warnx("%s: error allocating CCB", __func__);
6986		return (1);
6987	}
6988
6989	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->smpio);
6990
6991	while ((c = getopt(argc, argv, combinedopt)) != -1) {
6992		switch (c) {
6993		case 'R':
6994			arglist |= CAM_ARG_CMD_IN;
6995			response_size = strtol(optarg, NULL, 0);
6996			if (response_size <= 0) {
6997				warnx("invalid number of response bytes %d",
6998				      response_size);
6999				error = 1;
7000				goto smpcmd_bailout;
7001			}
7002			hook.argc = argc - optind;
7003			hook.argv = argv + optind;
7004			hook.got = 0;
7005			optind++;
7006			datastr = cget(&hook, NULL);
7007			/*
7008			 * If the user supplied "-" instead of a format, he
7009			 * wants the data to be written to stdout.
7010			 */
7011			if ((datastr != NULL)
7012			 && (datastr[0] == '-'))
7013				fd_response = 1;
7014
7015			smp_response = (u_int8_t *)malloc(response_size);
7016			if (smp_response == NULL) {
7017				warn("can't malloc memory for SMP response");
7018				error = 1;
7019				goto smpcmd_bailout;
7020			}
7021			break;
7022		case 'r':
7023			arglist |= CAM_ARG_CMD_OUT;
7024			request_size = strtol(optarg, NULL, 0);
7025			if (request_size <= 0) {
7026				warnx("invalid number of request bytes %d",
7027				      request_size);
7028				error = 1;
7029				goto smpcmd_bailout;
7030			}
7031			hook.argc = argc - optind;
7032			hook.argv = argv + optind;
7033			hook.got = 0;
7034			datastr = cget(&hook, NULL);
7035			smp_request = (u_int8_t *)malloc(request_size);
7036			if (smp_request == NULL) {
7037				warn("can't malloc memory for SMP request");
7038				error = 1;
7039				goto smpcmd_bailout;
7040			}
7041			bzero(smp_request, request_size);
7042			/*
7043			 * If the user supplied "-" instead of a format, he
7044			 * wants the data to be read from stdin.
7045			 */
7046			if ((datastr != NULL)
7047			 && (datastr[0] == '-'))
7048				fd_request = 1;
7049			else
7050				buff_encode_visit(smp_request, request_size,
7051						  datastr,
7052						  iget, &hook);
7053			optind += hook.got;
7054			break;
7055		default:
7056			break;
7057		}
7058	}
7059
7060	/*
7061	 * If fd_data is set, and we're writing to the device, we need to
7062	 * read the data the user wants written from stdin.
7063	 */
7064	if ((fd_request == 1) && (arglist & CAM_ARG_CMD_OUT)) {
7065		ssize_t amt_read;
7066		int amt_to_read = request_size;
7067		u_int8_t *buf_ptr = smp_request;
7068
7069		for (amt_read = 0; amt_to_read > 0;
7070		     amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) {
7071			if (amt_read == -1) {
7072				warn("error reading data from stdin");
7073				error = 1;
7074				goto smpcmd_bailout;
7075			}
7076			amt_to_read -= amt_read;
7077			buf_ptr += amt_read;
7078		}
7079	}
7080
7081	if (((arglist & CAM_ARG_CMD_IN) == 0)
7082	 || ((arglist & CAM_ARG_CMD_OUT) == 0)) {
7083		warnx("%s: need both the request (-r) and response (-R) "
7084		      "arguments", __func__);
7085		error = 1;
7086		goto smpcmd_bailout;
7087	}
7088
7089	flags |= CAM_DEV_QFRZDIS;
7090
7091	cam_fill_smpio(&ccb->smpio,
7092		       /*retries*/ retry_count,
7093		       /*cbfcnp*/ NULL,
7094		       /*flags*/ flags,
7095		       /*smp_request*/ smp_request,
7096		       /*smp_request_len*/ request_size,
7097		       /*smp_response*/ smp_response,
7098		       /*smp_response_len*/ response_size,
7099		       /*timeout*/ timeout ? timeout : 5000);
7100
7101	ccb->smpio.flags = SMP_FLAG_NONE;
7102
7103	if (((retval = cam_send_ccb(device, ccb)) < 0)
7104	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
7105		const char warnstr[] = "error sending command";
7106
7107		if (retval < 0)
7108			warn(warnstr);
7109		else
7110			warnx(warnstr);
7111
7112		if (arglist & CAM_ARG_VERBOSE) {
7113			cam_error_print(device, ccb, CAM_ESF_ALL,
7114					CAM_EPF_ALL, stderr);
7115		}
7116	}
7117
7118	if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
7119	 && (response_size > 0)) {
7120		if (fd_response == 0) {
7121			buff_decode_visit(smp_response, response_size,
7122					  datastr, arg_put, NULL);
7123			fprintf(stdout, "\n");
7124		} else {
7125			ssize_t amt_written;
7126			int amt_to_write = response_size;
7127			u_int8_t *buf_ptr = smp_response;
7128
7129			for (amt_written = 0; (amt_to_write > 0) &&
7130			     (amt_written = write(STDOUT_FILENO, buf_ptr,
7131						  amt_to_write)) > 0;){
7132				amt_to_write -= amt_written;
7133				buf_ptr += amt_written;
7134			}
7135			if (amt_written == -1) {
7136				warn("error writing data to stdout");
7137				error = 1;
7138				goto smpcmd_bailout;
7139			} else if ((amt_written == 0)
7140				&& (amt_to_write > 0)) {
7141				warnx("only wrote %u bytes out of %u",
7142				      response_size - amt_to_write,
7143				      response_size);
7144			}
7145		}
7146	}
7147smpcmd_bailout:
7148	if (ccb != NULL)
7149		cam_freeccb(ccb);
7150
7151	if (smp_request != NULL)
7152		free(smp_request);
7153
7154	if (smp_response != NULL)
7155		free(smp_response);
7156
7157	return (error);
7158}
7159
7160static int
7161smpreportgeneral(struct cam_device *device, int argc, char **argv,
7162		 char *combinedopt, int retry_count, int timeout)
7163{
7164	union ccb *ccb;
7165	struct smp_report_general_request *request = NULL;
7166	struct smp_report_general_response *response = NULL;
7167	struct sbuf *sb = NULL;
7168	int error = 0;
7169	int c, long_response = 0;
7170	int retval;
7171
7172	/*
7173	 * Note that at the moment we don't support sending SMP CCBs to
7174	 * devices that aren't probed by CAM.
7175	 */
7176	ccb = cam_getccb(device);
7177	if (ccb == NULL) {
7178		warnx("%s: error allocating CCB", __func__);
7179		return (1);
7180	}
7181
7182	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->smpio);
7183
7184	while ((c = getopt(argc, argv, combinedopt)) != -1) {
7185		switch (c) {
7186		case 'l':
7187			long_response = 1;
7188			break;
7189		default:
7190			break;
7191		}
7192	}
7193	request = malloc(sizeof(*request));
7194	if (request == NULL) {
7195		warn("%s: unable to allocate %zd bytes", __func__,
7196		     sizeof(*request));
7197		error = 1;
7198		goto bailout;
7199	}
7200
7201	response = malloc(sizeof(*response));
7202	if (response == NULL) {
7203		warn("%s: unable to allocate %zd bytes", __func__,
7204		     sizeof(*response));
7205		error = 1;
7206		goto bailout;
7207	}
7208
7209try_long:
7210	smp_report_general(&ccb->smpio,
7211			   retry_count,
7212			   /*cbfcnp*/ NULL,
7213			   request,
7214			   /*request_len*/ sizeof(*request),
7215			   (uint8_t *)response,
7216			   /*response_len*/ sizeof(*response),
7217			   /*long_response*/ long_response,
7218			   timeout);
7219
7220	if (((retval = cam_send_ccb(device, ccb)) < 0)
7221	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
7222		const char warnstr[] = "error sending command";
7223
7224		if (retval < 0)
7225			warn(warnstr);
7226		else
7227			warnx(warnstr);
7228
7229		if (arglist & CAM_ARG_VERBOSE) {
7230			cam_error_print(device, ccb, CAM_ESF_ALL,
7231					CAM_EPF_ALL, stderr);
7232		}
7233		error = 1;
7234		goto bailout;
7235	}
7236
7237	/*
7238	 * If the device supports the long response bit, try again and see
7239	 * if we can get all of the data.
7240	 */
7241	if ((response->long_response & SMP_RG_LONG_RESPONSE)
7242	 && (long_response == 0)) {
7243		ccb->ccb_h.status = CAM_REQ_INPROG;
7244		CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->smpio);
7245		long_response = 1;
7246		goto try_long;
7247	}
7248
7249	/*
7250	 * XXX KDM detect and decode SMP errors here.
7251	 */
7252	sb = sbuf_new_auto();
7253	if (sb == NULL) {
7254		warnx("%s: error allocating sbuf", __func__);
7255		goto bailout;
7256	}
7257
7258	smp_report_general_sbuf(response, sizeof(*response), sb);
7259
7260	if (sbuf_finish(sb) != 0) {
7261		warnx("%s: sbuf_finish", __func__);
7262		goto bailout;
7263	}
7264
7265	printf("%s", sbuf_data(sb));
7266
7267bailout:
7268	if (ccb != NULL)
7269		cam_freeccb(ccb);
7270
7271	if (request != NULL)
7272		free(request);
7273
7274	if (response != NULL)
7275		free(response);
7276
7277	if (sb != NULL)
7278		sbuf_delete(sb);
7279
7280	return (error);
7281}
7282
7283static struct camcontrol_opts phy_ops[] = {
7284	{"nop", SMP_PC_PHY_OP_NOP, CAM_ARG_NONE, NULL},
7285	{"linkreset", SMP_PC_PHY_OP_LINK_RESET, CAM_ARG_NONE, NULL},
7286	{"hardreset", SMP_PC_PHY_OP_HARD_RESET, CAM_ARG_NONE, NULL},
7287	{"disable", SMP_PC_PHY_OP_DISABLE, CAM_ARG_NONE, NULL},
7288	{"clearerrlog", SMP_PC_PHY_OP_CLEAR_ERR_LOG, CAM_ARG_NONE, NULL},
7289	{"clearaffiliation", SMP_PC_PHY_OP_CLEAR_AFFILIATON, CAM_ARG_NONE,NULL},
7290	{"sataportsel", SMP_PC_PHY_OP_TRANS_SATA_PSS, CAM_ARG_NONE, NULL},
7291	{"clearitnl", SMP_PC_PHY_OP_CLEAR_STP_ITN_LS, CAM_ARG_NONE, NULL},
7292	{"setdevname", SMP_PC_PHY_OP_SET_ATT_DEV_NAME, CAM_ARG_NONE, NULL},
7293	{NULL, 0, 0, NULL}
7294};
7295
7296static int
7297smpphycontrol(struct cam_device *device, int argc, char **argv,
7298	      char *combinedopt, int retry_count, int timeout)
7299{
7300	union ccb *ccb;
7301	struct smp_phy_control_request *request = NULL;
7302	struct smp_phy_control_response *response = NULL;
7303	int long_response = 0;
7304	int retval = 0;
7305	int phy = -1;
7306	uint32_t phy_operation = SMP_PC_PHY_OP_NOP;
7307	int phy_op_set = 0;
7308	uint64_t attached_dev_name = 0;
7309	int dev_name_set = 0;
7310	uint32_t min_plr = 0, max_plr = 0;
7311	uint32_t pp_timeout_val = 0;
7312	int slumber_partial = 0;
7313	int set_pp_timeout_val = 0;
7314	int c;
7315
7316	/*
7317	 * Note that at the moment we don't support sending SMP CCBs to
7318	 * devices that aren't probed by CAM.
7319	 */
7320	ccb = cam_getccb(device);
7321	if (ccb == NULL) {
7322		warnx("%s: error allocating CCB", __func__);
7323		return (1);
7324	}
7325
7326	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->smpio);
7327
7328	while ((c = getopt(argc, argv, combinedopt)) != -1) {
7329		switch (c) {
7330		case 'a':
7331		case 'A':
7332		case 's':
7333		case 'S': {
7334			int enable = -1;
7335
7336			if (strcasecmp(optarg, "enable") == 0)
7337				enable = 1;
7338			else if (strcasecmp(optarg, "disable") == 0)
7339				enable = 2;
7340			else {
7341				warnx("%s: Invalid argument %s", __func__,
7342				      optarg);
7343				retval = 1;
7344				goto bailout;
7345			}
7346			switch (c) {
7347			case 's':
7348				slumber_partial |= enable <<
7349						   SMP_PC_SAS_SLUMBER_SHIFT;
7350				break;
7351			case 'S':
7352				slumber_partial |= enable <<
7353						   SMP_PC_SAS_PARTIAL_SHIFT;
7354				break;
7355			case 'a':
7356				slumber_partial |= enable <<
7357						   SMP_PC_SATA_SLUMBER_SHIFT;
7358				break;
7359			case 'A':
7360				slumber_partial |= enable <<
7361						   SMP_PC_SATA_PARTIAL_SHIFT;
7362				break;
7363			default:
7364				warnx("%s: programmer error", __func__);
7365				retval = 1;
7366				goto bailout;
7367				break; /*NOTREACHED*/
7368			}
7369			break;
7370		}
7371		case 'd':
7372			attached_dev_name = (uintmax_t)strtoumax(optarg,
7373								 NULL,0);
7374			dev_name_set = 1;
7375			break;
7376		case 'l':
7377			long_response = 1;
7378			break;
7379		case 'm':
7380			/*
7381			 * We don't do extensive checking here, so this
7382			 * will continue to work when new speeds come out.
7383			 */
7384			min_plr = strtoul(optarg, NULL, 0);
7385			if ((min_plr == 0)
7386			 || (min_plr > 0xf)) {
7387				warnx("%s: invalid link rate %x",
7388				      __func__, min_plr);
7389				retval = 1;
7390				goto bailout;
7391			}
7392			break;
7393		case 'M':
7394			/*
7395			 * We don't do extensive checking here, so this
7396			 * will continue to work when new speeds come out.
7397			 */
7398			max_plr = strtoul(optarg, NULL, 0);
7399			if ((max_plr == 0)
7400			 || (max_plr > 0xf)) {
7401				warnx("%s: invalid link rate %x",
7402				      __func__, max_plr);
7403				retval = 1;
7404				goto bailout;
7405			}
7406			break;
7407		case 'o': {
7408			camcontrol_optret optreturn;
7409			cam_argmask argnums;
7410			const char *subopt;
7411
7412			if (phy_op_set != 0) {
7413				warnx("%s: only one phy operation argument "
7414				      "(-o) allowed", __func__);
7415				retval = 1;
7416				goto bailout;
7417			}
7418
7419			phy_op_set = 1;
7420
7421			/*
7422			 * Allow the user to specify the phy operation
7423			 * numerically, as well as with a name.  This will
7424			 * future-proof it a bit, so options that are added
7425			 * in future specs can be used.
7426			 */
7427			if (isdigit(optarg[0])) {
7428				phy_operation = strtoul(optarg, NULL, 0);
7429				if ((phy_operation == 0)
7430				 || (phy_operation > 0xff)) {
7431					warnx("%s: invalid phy operation %#x",
7432					      __func__, phy_operation);
7433					retval = 1;
7434					goto bailout;
7435				}
7436				break;
7437			}
7438			optreturn = getoption(phy_ops, optarg, &phy_operation,
7439					      &argnums, &subopt);
7440
7441			if (optreturn == CC_OR_AMBIGUOUS) {
7442				warnx("%s: ambiguous option %s", __func__,
7443				      optarg);
7444				usage(0);
7445				retval = 1;
7446				goto bailout;
7447			} else if (optreturn == CC_OR_NOT_FOUND) {
7448				warnx("%s: option %s not found", __func__,
7449				      optarg);
7450				usage(0);
7451				retval = 1;
7452				goto bailout;
7453			}
7454			break;
7455		}
7456		case 'p':
7457			phy = atoi(optarg);
7458			break;
7459		case 'T':
7460			pp_timeout_val = strtoul(optarg, NULL, 0);
7461			if (pp_timeout_val > 15) {
7462				warnx("%s: invalid partial pathway timeout "
7463				      "value %u, need a value less than 16",
7464				      __func__, pp_timeout_val);
7465				retval = 1;
7466				goto bailout;
7467			}
7468			set_pp_timeout_val = 1;
7469			break;
7470		default:
7471			break;
7472		}
7473	}
7474
7475	if (phy == -1) {
7476		warnx("%s: a PHY (-p phy) argument is required",__func__);
7477		retval = 1;
7478		goto bailout;
7479	}
7480
7481	if (((dev_name_set != 0)
7482	  && (phy_operation != SMP_PC_PHY_OP_SET_ATT_DEV_NAME))
7483	 || ((phy_operation == SMP_PC_PHY_OP_SET_ATT_DEV_NAME)
7484	  && (dev_name_set == 0))) {
7485		warnx("%s: -d name and -o setdevname arguments both "
7486		      "required to set device name", __func__);
7487		retval = 1;
7488		goto bailout;
7489	}
7490
7491	request = malloc(sizeof(*request));
7492	if (request == NULL) {
7493		warn("%s: unable to allocate %zd bytes", __func__,
7494		     sizeof(*request));
7495		retval = 1;
7496		goto bailout;
7497	}
7498
7499	response = malloc(sizeof(*response));
7500	if (response == NULL) {
7501		warn("%s: unable to allocate %zd bytes", __func__,
7502		     sizeof(*response));
7503		retval = 1;
7504		goto bailout;
7505	}
7506
7507	smp_phy_control(&ccb->smpio,
7508			retry_count,
7509			/*cbfcnp*/ NULL,
7510			request,
7511			sizeof(*request),
7512			(uint8_t *)response,
7513			sizeof(*response),
7514			long_response,
7515			/*expected_exp_change_count*/ 0,
7516			phy,
7517			phy_operation,
7518			(set_pp_timeout_val != 0) ? 1 : 0,
7519			attached_dev_name,
7520			min_plr,
7521			max_plr,
7522			slumber_partial,
7523			pp_timeout_val,
7524			timeout);
7525
7526	if (((retval = cam_send_ccb(device, ccb)) < 0)
7527	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
7528		const char warnstr[] = "error sending command";
7529
7530		if (retval < 0)
7531			warn(warnstr);
7532		else
7533			warnx(warnstr);
7534
7535		if (arglist & CAM_ARG_VERBOSE) {
7536			/*
7537			 * Use CAM_EPF_NORMAL so we only get one line of
7538			 * SMP command decoding.
7539			 */
7540			cam_error_print(device, ccb, CAM_ESF_ALL,
7541					CAM_EPF_NORMAL, stderr);
7542		}
7543		retval = 1;
7544		goto bailout;
7545	}
7546
7547	/* XXX KDM print out something here for success? */
7548bailout:
7549	if (ccb != NULL)
7550		cam_freeccb(ccb);
7551
7552	if (request != NULL)
7553		free(request);
7554
7555	if (response != NULL)
7556		free(response);
7557
7558	return (retval);
7559}
7560
7561static int
7562smpmaninfo(struct cam_device *device, int argc, char **argv,
7563	   char *combinedopt, int retry_count, int timeout)
7564{
7565	union ccb *ccb;
7566	struct smp_report_manuf_info_request request;
7567	struct smp_report_manuf_info_response response;
7568	struct sbuf *sb = NULL;
7569	int long_response = 0;
7570	int retval = 0;
7571	int c;
7572
7573	/*
7574	 * Note that at the moment we don't support sending SMP CCBs to
7575	 * devices that aren't probed by CAM.
7576	 */
7577	ccb = cam_getccb(device);
7578	if (ccb == NULL) {
7579		warnx("%s: error allocating CCB", __func__);
7580		return (1);
7581	}
7582
7583	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->smpio);
7584
7585	while ((c = getopt(argc, argv, combinedopt)) != -1) {
7586		switch (c) {
7587		case 'l':
7588			long_response = 1;
7589			break;
7590		default:
7591			break;
7592		}
7593	}
7594	bzero(&request, sizeof(request));
7595	bzero(&response, sizeof(response));
7596
7597	smp_report_manuf_info(&ccb->smpio,
7598			      retry_count,
7599			      /*cbfcnp*/ NULL,
7600			      &request,
7601			      sizeof(request),
7602			      (uint8_t *)&response,
7603			      sizeof(response),
7604			      long_response,
7605			      timeout);
7606
7607	if (((retval = cam_send_ccb(device, ccb)) < 0)
7608	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
7609		const char warnstr[] = "error sending command";
7610
7611		if (retval < 0)
7612			warn(warnstr);
7613		else
7614			warnx(warnstr);
7615
7616		if (arglist & CAM_ARG_VERBOSE) {
7617			cam_error_print(device, ccb, CAM_ESF_ALL,
7618					CAM_EPF_ALL, stderr);
7619		}
7620		retval = 1;
7621		goto bailout;
7622	}
7623
7624	sb = sbuf_new_auto();
7625	if (sb == NULL) {
7626		warnx("%s: error allocating sbuf", __func__);
7627		goto bailout;
7628	}
7629
7630	smp_report_manuf_info_sbuf(&response, sizeof(response), sb);
7631
7632	if (sbuf_finish(sb) != 0) {
7633		warnx("%s: sbuf_finish", __func__);
7634		goto bailout;
7635	}
7636
7637	printf("%s", sbuf_data(sb));
7638
7639bailout:
7640
7641	if (ccb != NULL)
7642		cam_freeccb(ccb);
7643
7644	if (sb != NULL)
7645		sbuf_delete(sb);
7646
7647	return (retval);
7648}
7649
7650static int
7651getdevid(struct cam_devitem *item)
7652{
7653	int retval = 0;
7654	union ccb *ccb = NULL;
7655
7656	struct cam_device *dev;
7657
7658	dev = cam_open_btl(item->dev_match.path_id,
7659			   item->dev_match.target_id,
7660			   item->dev_match.target_lun, O_RDWR, NULL);
7661
7662	if (dev == NULL) {
7663		warnx("%s", cam_errbuf);
7664		retval = 1;
7665		goto bailout;
7666	}
7667
7668	item->device_id_len = 0;
7669
7670	ccb = cam_getccb(dev);
7671	if (ccb == NULL) {
7672		warnx("%s: error allocating CCB", __func__);
7673		retval = 1;
7674		goto bailout;
7675	}
7676
7677	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->cdai);
7678
7679	/*
7680	 * On the first try, we just probe for the size of the data, and
7681	 * then allocate that much memory and try again.
7682	 */
7683retry:
7684	ccb->ccb_h.func_code = XPT_DEV_ADVINFO;
7685	ccb->ccb_h.flags = CAM_DIR_IN;
7686	ccb->cdai.flags = CDAI_FLAG_NONE;
7687	ccb->cdai.buftype = CDAI_TYPE_SCSI_DEVID;
7688	ccb->cdai.bufsiz = item->device_id_len;
7689	if (item->device_id_len != 0)
7690		ccb->cdai.buf = (uint8_t *)item->device_id;
7691
7692	if (cam_send_ccb(dev, ccb) < 0) {
7693		warn("%s: error sending XPT_GDEV_ADVINFO CCB", __func__);
7694		retval = 1;
7695		goto bailout;
7696	}
7697
7698	if (ccb->ccb_h.status != CAM_REQ_CMP) {
7699		warnx("%s: CAM status %#x", __func__, ccb->ccb_h.status);
7700		retval = 1;
7701		goto bailout;
7702	}
7703
7704	if (item->device_id_len == 0) {
7705		/*
7706		 * This is our first time through.  Allocate the buffer,
7707		 * and then go back to get the data.
7708		 */
7709		if (ccb->cdai.provsiz == 0) {
7710			warnx("%s: invalid .provsiz field returned with "
7711			     "XPT_GDEV_ADVINFO CCB", __func__);
7712			retval = 1;
7713			goto bailout;
7714		}
7715		item->device_id_len = ccb->cdai.provsiz;
7716		item->device_id = malloc(item->device_id_len);
7717		if (item->device_id == NULL) {
7718			warn("%s: unable to allocate %d bytes", __func__,
7719			     item->device_id_len);
7720			retval = 1;
7721			goto bailout;
7722		}
7723		ccb->ccb_h.status = CAM_REQ_INPROG;
7724		goto retry;
7725	}
7726
7727bailout:
7728	if (dev != NULL)
7729		cam_close_device(dev);
7730
7731	if (ccb != NULL)
7732		cam_freeccb(ccb);
7733
7734	return (retval);
7735}
7736
7737/*
7738 * XXX KDM merge this code with getdevtree()?
7739 */
7740static int
7741buildbusdevlist(struct cam_devlist *devlist)
7742{
7743	union ccb ccb;
7744	int bufsize, fd = -1;
7745	struct dev_match_pattern *patterns;
7746	struct cam_devitem *item = NULL;
7747	int skip_device = 0;
7748	int retval = 0;
7749
7750	if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
7751		warn("couldn't open %s", XPT_DEVICE);
7752		return(1);
7753	}
7754
7755	bzero(&ccb, sizeof(union ccb));
7756
7757	ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
7758	ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
7759	ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
7760
7761	ccb.ccb_h.func_code = XPT_DEV_MATCH;
7762	bufsize = sizeof(struct dev_match_result) * 100;
7763	ccb.cdm.match_buf_len = bufsize;
7764	ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
7765	if (ccb.cdm.matches == NULL) {
7766		warnx("can't malloc memory for matches");
7767		close(fd);
7768		return(1);
7769	}
7770	ccb.cdm.num_matches = 0;
7771	ccb.cdm.num_patterns = 2;
7772	ccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern) *
7773		ccb.cdm.num_patterns;
7774
7775	patterns = (struct dev_match_pattern *)malloc(ccb.cdm.pattern_buf_len);
7776	if (patterns == NULL) {
7777		warnx("can't malloc memory for patterns");
7778		retval = 1;
7779		goto bailout;
7780	}
7781
7782	ccb.cdm.patterns = patterns;
7783	bzero(patterns, ccb.cdm.pattern_buf_len);
7784
7785	patterns[0].type = DEV_MATCH_DEVICE;
7786	patterns[0].pattern.device_pattern.flags = DEV_MATCH_PATH;
7787	patterns[0].pattern.device_pattern.path_id = devlist->path_id;
7788	patterns[1].type = DEV_MATCH_PERIPH;
7789	patterns[1].pattern.periph_pattern.flags = PERIPH_MATCH_PATH;
7790	patterns[1].pattern.periph_pattern.path_id = devlist->path_id;
7791
7792	/*
7793	 * We do the ioctl multiple times if necessary, in case there are
7794	 * more than 100 nodes in the EDT.
7795	 */
7796	do {
7797		unsigned int i;
7798
7799		if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
7800			warn("error sending CAMIOCOMMAND ioctl");
7801			retval = 1;
7802			goto bailout;
7803		}
7804
7805		if ((ccb.ccb_h.status != CAM_REQ_CMP)
7806		 || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
7807		    && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
7808			warnx("got CAM error %#x, CDM error %d\n",
7809			      ccb.ccb_h.status, ccb.cdm.status);
7810			retval = 1;
7811			goto bailout;
7812		}
7813
7814		for (i = 0; i < ccb.cdm.num_matches; i++) {
7815			switch (ccb.cdm.matches[i].type) {
7816			case DEV_MATCH_DEVICE: {
7817				struct device_match_result *dev_result;
7818
7819				dev_result =
7820				     &ccb.cdm.matches[i].result.device_result;
7821
7822				if (dev_result->flags &
7823				    DEV_RESULT_UNCONFIGURED) {
7824					skip_device = 1;
7825					break;
7826				} else
7827					skip_device = 0;
7828
7829				item = malloc(sizeof(*item));
7830				if (item == NULL) {
7831					warn("%s: unable to allocate %zd bytes",
7832					     __func__, sizeof(*item));
7833					retval = 1;
7834					goto bailout;
7835				}
7836				bzero(item, sizeof(*item));
7837				bcopy(dev_result, &item->dev_match,
7838				      sizeof(*dev_result));
7839				STAILQ_INSERT_TAIL(&devlist->dev_queue, item,
7840						   links);
7841
7842				if (getdevid(item) != 0) {
7843					retval = 1;
7844					goto bailout;
7845				}
7846				break;
7847			}
7848			case DEV_MATCH_PERIPH: {
7849				struct periph_match_result *periph_result;
7850
7851				periph_result =
7852				      &ccb.cdm.matches[i].result.periph_result;
7853
7854				if (skip_device != 0)
7855					break;
7856				item->num_periphs++;
7857				item->periph_matches = realloc(
7858					item->periph_matches,
7859					item->num_periphs *
7860					sizeof(struct periph_match_result));
7861				if (item->periph_matches == NULL) {
7862					warn("%s: error allocating periph "
7863					     "list", __func__);
7864					retval = 1;
7865					goto bailout;
7866				}
7867				bcopy(periph_result, &item->periph_matches[
7868				      item->num_periphs - 1],
7869				      sizeof(*periph_result));
7870				break;
7871			}
7872			default:
7873				fprintf(stderr, "%s: unexpected match "
7874					"type %d\n", __func__,
7875					ccb.cdm.matches[i].type);
7876				retval = 1;
7877				goto bailout;
7878				break; /*NOTREACHED*/
7879			}
7880		}
7881	} while ((ccb.ccb_h.status == CAM_REQ_CMP)
7882		&& (ccb.cdm.status == CAM_DEV_MATCH_MORE));
7883bailout:
7884
7885	if (fd != -1)
7886		close(fd);
7887
7888	free(patterns);
7889
7890	free(ccb.cdm.matches);
7891
7892	if (retval != 0)
7893		freebusdevlist(devlist);
7894
7895	return (retval);
7896}
7897
7898static void
7899freebusdevlist(struct cam_devlist *devlist)
7900{
7901	struct cam_devitem *item, *item2;
7902
7903	STAILQ_FOREACH_SAFE(item, &devlist->dev_queue, links, item2) {
7904		STAILQ_REMOVE(&devlist->dev_queue, item, cam_devitem,
7905			      links);
7906		free(item->device_id);
7907		free(item->periph_matches);
7908		free(item);
7909	}
7910}
7911
7912static struct cam_devitem *
7913findsasdevice(struct cam_devlist *devlist, uint64_t sasaddr)
7914{
7915	struct cam_devitem *item;
7916
7917	STAILQ_FOREACH(item, &devlist->dev_queue, links) {
7918		struct scsi_vpd_id_descriptor *idd;
7919
7920		/*
7921		 * XXX KDM look for LUN IDs as well?
7922		 */
7923		idd = scsi_get_devid(item->device_id,
7924					   item->device_id_len,
7925					   scsi_devid_is_sas_target);
7926		if (idd == NULL)
7927			continue;
7928
7929		if (scsi_8btou64(idd->identifier) == sasaddr)
7930			return (item);
7931	}
7932
7933	return (NULL);
7934}
7935
7936static int
7937smpphylist(struct cam_device *device, int argc, char **argv,
7938	   char *combinedopt, int retry_count, int timeout)
7939{
7940	struct smp_report_general_request *rgrequest = NULL;
7941	struct smp_report_general_response *rgresponse = NULL;
7942	struct smp_discover_request *disrequest = NULL;
7943	struct smp_discover_response *disresponse = NULL;
7944	struct cam_devlist devlist;
7945	union ccb *ccb;
7946	int long_response = 0;
7947	int num_phys = 0;
7948	int quiet = 0;
7949	int retval;
7950	int i, c;
7951
7952	/*
7953	 * Note that at the moment we don't support sending SMP CCBs to
7954	 * devices that aren't probed by CAM.
7955	 */
7956	ccb = cam_getccb(device);
7957	if (ccb == NULL) {
7958		warnx("%s: error allocating CCB", __func__);
7959		return (1);
7960	}
7961
7962	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->smpio);
7963	STAILQ_INIT(&devlist.dev_queue);
7964
7965	rgrequest = malloc(sizeof(*rgrequest));
7966	if (rgrequest == NULL) {
7967		warn("%s: unable to allocate %zd bytes", __func__,
7968		     sizeof(*rgrequest));
7969		retval = 1;
7970		goto bailout;
7971	}
7972
7973	rgresponse = malloc(sizeof(*rgresponse));
7974	if (rgresponse == NULL) {
7975		warn("%s: unable to allocate %zd bytes", __func__,
7976		     sizeof(*rgresponse));
7977		retval = 1;
7978		goto bailout;
7979	}
7980
7981	while ((c = getopt(argc, argv, combinedopt)) != -1) {
7982		switch (c) {
7983		case 'l':
7984			long_response = 1;
7985			break;
7986		case 'q':
7987			quiet = 1;
7988			break;
7989		default:
7990			break;
7991		}
7992	}
7993
7994	smp_report_general(&ccb->smpio,
7995			   retry_count,
7996			   /*cbfcnp*/ NULL,
7997			   rgrequest,
7998			   /*request_len*/ sizeof(*rgrequest),
7999			   (uint8_t *)rgresponse,
8000			   /*response_len*/ sizeof(*rgresponse),
8001			   /*long_response*/ long_response,
8002			   timeout);
8003
8004	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
8005
8006	if (((retval = cam_send_ccb(device, ccb)) < 0)
8007	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
8008		const char warnstr[] = "error sending command";
8009
8010		if (retval < 0)
8011			warn(warnstr);
8012		else
8013			warnx(warnstr);
8014
8015		if (arglist & CAM_ARG_VERBOSE) {
8016			cam_error_print(device, ccb, CAM_ESF_ALL,
8017					CAM_EPF_ALL, stderr);
8018		}
8019		retval = 1;
8020		goto bailout;
8021	}
8022
8023	num_phys = rgresponse->num_phys;
8024
8025	if (num_phys == 0) {
8026		if (quiet == 0)
8027			fprintf(stdout, "%s: No Phys reported\n", __func__);
8028		retval = 1;
8029		goto bailout;
8030	}
8031
8032	devlist.path_id = device->path_id;
8033
8034	retval = buildbusdevlist(&devlist);
8035	if (retval != 0)
8036		goto bailout;
8037
8038	if (quiet == 0) {
8039		fprintf(stdout, "%d PHYs:\n", num_phys);
8040		fprintf(stdout, "PHY  Attached SAS Address\n");
8041	}
8042
8043	disrequest = malloc(sizeof(*disrequest));
8044	if (disrequest == NULL) {
8045		warn("%s: unable to allocate %zd bytes", __func__,
8046		     sizeof(*disrequest));
8047		retval = 1;
8048		goto bailout;
8049	}
8050
8051	disresponse = malloc(sizeof(*disresponse));
8052	if (disresponse == NULL) {
8053		warn("%s: unable to allocate %zd bytes", __func__,
8054		     sizeof(*disresponse));
8055		retval = 1;
8056		goto bailout;
8057	}
8058
8059	for (i = 0; i < num_phys; i++) {
8060		struct cam_devitem *item;
8061		struct device_match_result *dev_match;
8062		char vendor[16], product[48], revision[16];
8063		char tmpstr[256];
8064		int j;
8065
8066		CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->smpio);
8067
8068		ccb->ccb_h.status = CAM_REQ_INPROG;
8069		ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
8070
8071		smp_discover(&ccb->smpio,
8072			     retry_count,
8073			     /*cbfcnp*/ NULL,
8074			     disrequest,
8075			     sizeof(*disrequest),
8076			     (uint8_t *)disresponse,
8077			     sizeof(*disresponse),
8078			     long_response,
8079			     /*ignore_zone_group*/ 0,
8080			     /*phy*/ i,
8081			     timeout);
8082
8083		if (((retval = cam_send_ccb(device, ccb)) < 0)
8084		 || (((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
8085		  && (disresponse->function_result != SMP_FR_PHY_VACANT))) {
8086			const char warnstr[] = "error sending command";
8087
8088			if (retval < 0)
8089				warn(warnstr);
8090			else
8091				warnx(warnstr);
8092
8093			if (arglist & CAM_ARG_VERBOSE) {
8094				cam_error_print(device, ccb, CAM_ESF_ALL,
8095						CAM_EPF_ALL, stderr);
8096			}
8097			retval = 1;
8098			goto bailout;
8099		}
8100
8101		if (disresponse->function_result == SMP_FR_PHY_VACANT) {
8102			if (quiet == 0)
8103				fprintf(stdout, "%3d  <vacant>\n", i);
8104			continue;
8105		}
8106
8107		if (disresponse->attached_device == SMP_DIS_AD_TYPE_NONE) {
8108			item = NULL;
8109		} else {
8110			item = findsasdevice(&devlist,
8111			    scsi_8btou64(disresponse->attached_sas_address));
8112		}
8113
8114		if ((quiet == 0)
8115		 || (item != NULL)) {
8116			fprintf(stdout, "%3d  0x%016jx", i,
8117				(uintmax_t)scsi_8btou64(
8118				disresponse->attached_sas_address));
8119			if (item == NULL) {
8120				fprintf(stdout, "\n");
8121				continue;
8122			}
8123		} else if (quiet != 0)
8124			continue;
8125
8126		dev_match = &item->dev_match;
8127
8128		if (dev_match->protocol == PROTO_SCSI) {
8129			cam_strvis(vendor, dev_match->inq_data.vendor,
8130				   sizeof(dev_match->inq_data.vendor),
8131				   sizeof(vendor));
8132			cam_strvis(product, dev_match->inq_data.product,
8133				   sizeof(dev_match->inq_data.product),
8134				   sizeof(product));
8135			cam_strvis(revision, dev_match->inq_data.revision,
8136				   sizeof(dev_match->inq_data.revision),
8137				   sizeof(revision));
8138			sprintf(tmpstr, "<%s %s %s>", vendor, product,
8139				revision);
8140		} else if ((dev_match->protocol == PROTO_ATA)
8141			|| (dev_match->protocol == PROTO_SATAPM)) {
8142			cam_strvis(product, dev_match->ident_data.model,
8143				   sizeof(dev_match->ident_data.model),
8144				   sizeof(product));
8145			cam_strvis(revision, dev_match->ident_data.revision,
8146				   sizeof(dev_match->ident_data.revision),
8147				   sizeof(revision));
8148			sprintf(tmpstr, "<%s %s>", product, revision);
8149		} else {
8150			sprintf(tmpstr, "<>");
8151		}
8152		fprintf(stdout, "   %-33s ", tmpstr);
8153
8154		/*
8155		 * If we have 0 periphs, that's a bug...
8156		 */
8157		if (item->num_periphs == 0) {
8158			fprintf(stdout, "\n");
8159			continue;
8160		}
8161
8162		fprintf(stdout, "(");
8163		for (j = 0; j < item->num_periphs; j++) {
8164			if (j > 0)
8165				fprintf(stdout, ",");
8166
8167			fprintf(stdout, "%s%d",
8168				item->periph_matches[j].periph_name,
8169				item->periph_matches[j].unit_number);
8170
8171		}
8172		fprintf(stdout, ")\n");
8173	}
8174bailout:
8175	if (ccb != NULL)
8176		cam_freeccb(ccb);
8177
8178	free(rgrequest);
8179
8180	free(rgresponse);
8181
8182	free(disrequest);
8183
8184	free(disresponse);
8185
8186	freebusdevlist(&devlist);
8187
8188	return (retval);
8189}
8190
8191static int
8192atapm(struct cam_device *device, int argc, char **argv,
8193		 char *combinedopt, int retry_count, int timeout)
8194{
8195	union ccb *ccb;
8196	int retval = 0;
8197	int t = -1;
8198	int c;
8199	u_char cmd, sc;
8200
8201	ccb = cam_getccb(device);
8202
8203	if (ccb == NULL) {
8204		warnx("%s: error allocating ccb", __func__);
8205		return (1);
8206	}
8207
8208	while ((c = getopt(argc, argv, combinedopt)) != -1) {
8209		switch (c) {
8210		case 't':
8211			t = atoi(optarg);
8212			break;
8213		default:
8214			break;
8215		}
8216	}
8217	if (strcmp(argv[1], "idle") == 0) {
8218		if (t == -1)
8219			cmd = ATA_IDLE_IMMEDIATE;
8220		else
8221			cmd = ATA_IDLE_CMD;
8222	} else if (strcmp(argv[1], "standby") == 0) {
8223		if (t == -1)
8224			cmd = ATA_STANDBY_IMMEDIATE;
8225		else
8226			cmd = ATA_STANDBY_CMD;
8227	} else {
8228		cmd = ATA_SLEEP;
8229		t = -1;
8230	}
8231
8232	if (t < 0)
8233		sc = 0;
8234	else if (t <= (240 * 5))
8235		sc = (t + 4) / 5;
8236	else if (t <= (252 * 5))
8237		/* special encoding for 21 minutes */
8238		sc = 252;
8239	else if (t <= (11 * 30 * 60))
8240		sc = (t - 1) / (30 * 60) + 241;
8241	else
8242		sc = 253;
8243
8244	retval = ata_do_28bit_cmd(device,
8245	    ccb,
8246	    /*retries*/retry_count,
8247	    /*flags*/CAM_DIR_NONE,
8248	    /*protocol*/AP_PROTO_NON_DATA,
8249	    /*tag_action*/MSG_SIMPLE_Q_TAG,
8250	    /*command*/cmd,
8251	    /*features*/0,
8252	    /*lba*/0,
8253	    /*sector_count*/sc,
8254	    /*data_ptr*/NULL,
8255	    /*dxfer_len*/0,
8256	    /*timeout*/timeout ? timeout : 30 * 1000,
8257	    /*quiet*/1);
8258
8259	cam_freeccb(ccb);
8260	return (retval);
8261}
8262
8263static int
8264ataaxm(struct cam_device *device, int argc, char **argv,
8265		 char *combinedopt, int retry_count, int timeout)
8266{
8267	union ccb *ccb;
8268	int retval = 0;
8269	int l = -1;
8270	int c;
8271	u_char cmd, sc;
8272
8273	ccb = cam_getccb(device);
8274
8275	if (ccb == NULL) {
8276		warnx("%s: error allocating ccb", __func__);
8277		return (1);
8278	}
8279
8280	while ((c = getopt(argc, argv, combinedopt)) != -1) {
8281		switch (c) {
8282		case 'l':
8283			l = atoi(optarg);
8284			break;
8285		default:
8286			break;
8287		}
8288	}
8289	sc = 0;
8290	if (strcmp(argv[1], "apm") == 0) {
8291		if (l == -1)
8292			cmd = 0x85;
8293		else {
8294			cmd = 0x05;
8295			sc = l;
8296		}
8297	} else /* aam */ {
8298		if (l == -1)
8299			cmd = 0xC2;
8300		else {
8301			cmd = 0x42;
8302			sc = l;
8303		}
8304	}
8305
8306	retval = ata_do_28bit_cmd(device,
8307	    ccb,
8308	    /*retries*/retry_count,
8309	    /*flags*/CAM_DIR_NONE,
8310	    /*protocol*/AP_PROTO_NON_DATA,
8311	    /*tag_action*/MSG_SIMPLE_Q_TAG,
8312	    /*command*/ATA_SETFEATURES,
8313	    /*features*/cmd,
8314	    /*lba*/0,
8315	    /*sector_count*/sc,
8316	    /*data_ptr*/NULL,
8317	    /*dxfer_len*/0,
8318	    /*timeout*/timeout ? timeout : 30 * 1000,
8319	    /*quiet*/1);
8320
8321	cam_freeccb(ccb);
8322	return (retval);
8323}
8324
8325int
8326scsigetopcodes(struct cam_device *device, int opcode_set, int opcode,
8327	       int show_sa_errors, int sa_set, int service_action,
8328	       int timeout_desc, int task_attr, int retry_count, int timeout,
8329	       int verbosemode, uint32_t *fill_len, uint8_t **data_ptr)
8330{
8331	union ccb *ccb = NULL;
8332	uint8_t *buf = NULL;
8333	uint32_t alloc_len = 0, num_opcodes;
8334	uint32_t valid_len = 0;
8335	uint32_t avail_len = 0;
8336	struct scsi_report_supported_opcodes_all *all_hdr;
8337	struct scsi_report_supported_opcodes_one *one;
8338	int options = 0;
8339	int retval = 0;
8340
8341	/*
8342	 * Make it clear that we haven't yet allocated or filled anything.
8343	 */
8344	*fill_len = 0;
8345	*data_ptr = NULL;
8346
8347	ccb = cam_getccb(device);
8348	if (ccb == NULL) {
8349		warnx("couldn't allocate CCB");
8350		retval = 1;
8351		goto bailout;
8352	}
8353
8354	/* cam_getccb cleans up the header, caller has to zero the payload */
8355	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
8356
8357	if (opcode_set != 0) {
8358		options |= RSO_OPTIONS_OC;
8359		num_opcodes = 1;
8360		alloc_len = sizeof(*one) + CAM_MAX_CDBLEN;
8361	} else {
8362		num_opcodes = 256;
8363		alloc_len = sizeof(*all_hdr) + (num_opcodes *
8364		    sizeof(struct scsi_report_supported_opcodes_descr));
8365	}
8366
8367	if (timeout_desc != 0) {
8368		options |= RSO_RCTD;
8369		alloc_len += num_opcodes *
8370		    sizeof(struct scsi_report_supported_opcodes_timeout);
8371	}
8372
8373	if (sa_set != 0) {
8374		options |= RSO_OPTIONS_OC_SA;
8375		if (show_sa_errors != 0)
8376			options &= ~RSO_OPTIONS_OC;
8377	}
8378
8379retry_alloc:
8380	if (buf != NULL) {
8381		free(buf);
8382		buf = NULL;
8383	}
8384
8385	buf = malloc(alloc_len);
8386	if (buf == NULL) {
8387		warn("Unable to allocate %u bytes", alloc_len);
8388		retval = 1;
8389		goto bailout;
8390	}
8391	bzero(buf, alloc_len);
8392
8393	scsi_report_supported_opcodes(&ccb->csio,
8394				      /*retries*/ retry_count,
8395				      /*cbfcnp*/ NULL,
8396				      /*tag_action*/ task_attr,
8397				      /*options*/ options,
8398				      /*req_opcode*/ opcode,
8399				      /*req_service_action*/ service_action,
8400				      /*data_ptr*/ buf,
8401				      /*dxfer_len*/ alloc_len,
8402				      /*sense_len*/ SSD_FULL_SIZE,
8403				      /*timeout*/ timeout ? timeout : 10000);
8404
8405	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
8406
8407	if (retry_count != 0)
8408		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
8409
8410	if (cam_send_ccb(device, ccb) < 0) {
8411		perror("error sending REPORT SUPPORTED OPERATION CODES");
8412		retval = 1;
8413		goto bailout;
8414	}
8415
8416	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
8417		if (verbosemode != 0)
8418			cam_error_print(device, ccb, CAM_ESF_ALL,
8419					CAM_EPF_ALL, stderr);
8420
8421		retval = 1;
8422		goto bailout;
8423	}
8424
8425	valid_len = ccb->csio.dxfer_len - ccb->csio.resid;
8426
8427	if (((options & RSO_OPTIONS_MASK) == RSO_OPTIONS_ALL)
8428	 && (valid_len >= sizeof(*all_hdr))) {
8429		all_hdr = (struct scsi_report_supported_opcodes_all *)buf;
8430		avail_len = scsi_4btoul(all_hdr->length) + sizeof(*all_hdr);
8431	} else if (((options & RSO_OPTIONS_MASK) != RSO_OPTIONS_ALL)
8432		&& (valid_len >= sizeof(*one))) {
8433		uint32_t cdb_length;
8434
8435		one = (struct scsi_report_supported_opcodes_one *)buf;
8436		cdb_length = scsi_2btoul(one->cdb_length);
8437		avail_len = sizeof(*one) + cdb_length;
8438		if (one->support & RSO_ONE_CTDP) {
8439			struct scsi_report_supported_opcodes_timeout *td;
8440
8441			td = (struct scsi_report_supported_opcodes_timeout *)
8442			    &buf[avail_len];
8443			if (valid_len >= (avail_len + sizeof(td->length))) {
8444				avail_len += scsi_2btoul(td->length) +
8445				    sizeof(td->length);
8446			} else {
8447				avail_len += sizeof(*td);
8448			}
8449		}
8450	}
8451
8452	/*
8453	 * avail_len could be zero if we didn't get enough data back from
8454	 * thet target to determine
8455	 */
8456	if ((avail_len != 0)
8457	 && (avail_len > valid_len)) {
8458		alloc_len = avail_len;
8459		goto retry_alloc;
8460	}
8461
8462	*fill_len = valid_len;
8463	*data_ptr = buf;
8464bailout:
8465	if (retval != 0)
8466		free(buf);
8467
8468	cam_freeccb(ccb);
8469
8470	return (retval);
8471}
8472
8473static int
8474scsiprintoneopcode(struct cam_device *device, int req_opcode, int sa_set,
8475		   int req_sa, uint8_t *buf, uint32_t valid_len)
8476{
8477	struct scsi_report_supported_opcodes_one *one;
8478	struct scsi_report_supported_opcodes_timeout *td;
8479	uint32_t cdb_len = 0, td_len = 0;
8480	const char *op_desc = NULL;
8481	unsigned int i;
8482	int retval = 0;
8483
8484	one = (struct scsi_report_supported_opcodes_one *)buf;
8485
8486	/*
8487	 * If we don't have the full single opcode descriptor, no point in
8488	 * continuing.
8489	 */
8490	if (valid_len < __offsetof(struct scsi_report_supported_opcodes_one,
8491	    cdb_length)) {
8492		warnx("Only %u bytes returned, not enough to verify support",
8493		      valid_len);
8494		retval = 1;
8495		goto bailout;
8496	}
8497
8498	op_desc = scsi_op_desc(req_opcode, &device->inq_data);
8499
8500	printf("%s (0x%02x)", op_desc != NULL ? op_desc : "UNKNOWN",
8501	       req_opcode);
8502	if (sa_set != 0)
8503		printf(", SA 0x%x", req_sa);
8504	printf(": ");
8505
8506	switch (one->support & RSO_ONE_SUP_MASK) {
8507	case RSO_ONE_SUP_UNAVAIL:
8508		printf("No command support information currently available\n");
8509		break;
8510	case RSO_ONE_SUP_NOT_SUP:
8511		printf("Command not supported\n");
8512		retval = 1;
8513		goto bailout;
8514		break; /*NOTREACHED*/
8515	case RSO_ONE_SUP_AVAIL:
8516		printf("Command is supported, complies with a SCSI standard\n");
8517		break;
8518	case RSO_ONE_SUP_VENDOR:
8519		printf("Command is supported, vendor-specific "
8520		       "implementation\n");
8521		break;
8522	default:
8523		printf("Unknown command support flags 0x%#x\n",
8524		       one->support & RSO_ONE_SUP_MASK);
8525		break;
8526	}
8527
8528	/*
8529	 * If we don't have the CDB length, it isn't exactly an error, the
8530	 * command probably isn't supported.
8531	 */
8532	if (valid_len < __offsetof(struct scsi_report_supported_opcodes_one,
8533	    cdb_usage))
8534		goto bailout;
8535
8536	cdb_len = scsi_2btoul(one->cdb_length);
8537
8538	/*
8539	 * If our valid data doesn't include the full reported length,
8540	 * return.  The caller should have detected this and adjusted his
8541	 * allocation length to get all of the available data.
8542	 */
8543	if (valid_len < sizeof(*one) + cdb_len) {
8544		retval = 1;
8545		goto bailout;
8546	}
8547
8548	/*
8549	 * If all we have is the opcode, there is no point in printing out
8550	 * the usage bitmap.
8551	 */
8552	if (cdb_len <= 1) {
8553		retval = 1;
8554		goto bailout;
8555	}
8556
8557	printf("CDB usage bitmap:");
8558	for (i = 0; i < cdb_len; i++) {
8559		printf(" %02x", one->cdb_usage[i]);
8560	}
8561	printf("\n");
8562
8563	/*
8564	 * If we don't have a timeout descriptor, we're done.
8565	 */
8566	if ((one->support & RSO_ONE_CTDP) == 0)
8567		goto bailout;
8568
8569	/*
8570	 * If we don't have enough valid length to include the timeout
8571	 * descriptor length, we're done.
8572	 */
8573	if (valid_len < (sizeof(*one) + cdb_len + sizeof(td->length)))
8574		goto bailout;
8575
8576	td = (struct scsi_report_supported_opcodes_timeout *)
8577	    &buf[sizeof(*one) + cdb_len];
8578	td_len = scsi_2btoul(td->length);
8579	td_len += sizeof(td->length);
8580
8581	/*
8582	 * If we don't have the full timeout descriptor, we're done.
8583	 */
8584	if (td_len < sizeof(*td))
8585		goto bailout;
8586
8587	/*
8588	 * If we don't have enough valid length to contain the full timeout
8589	 * descriptor, we're done.
8590	 */
8591	if (valid_len < (sizeof(*one) + cdb_len + td_len))
8592		goto bailout;
8593
8594	printf("Timeout information:\n");
8595	printf("Command-specific:    0x%02x\n", td->cmd_specific);
8596	printf("Nominal timeout:     %u seconds\n",
8597	       scsi_4btoul(td->nominal_time));
8598	printf("Recommended timeout: %u seconds\n",
8599	       scsi_4btoul(td->recommended_time));
8600
8601bailout:
8602	return (retval);
8603}
8604
8605static int
8606scsiprintopcodes(struct cam_device *device, int td_req, uint8_t *buf,
8607		 uint32_t valid_len)
8608{
8609	struct scsi_report_supported_opcodes_all *hdr;
8610	struct scsi_report_supported_opcodes_descr *desc;
8611	uint32_t avail_len = 0, used_len = 0;
8612	uint8_t *cur_ptr;
8613	int retval = 0;
8614
8615	if (valid_len < sizeof(*hdr)) {
8616		warnx("%s: not enough returned data (%u bytes) opcode list",
8617		      __func__, valid_len);
8618		retval = 1;
8619		goto bailout;
8620	}
8621	hdr = (struct scsi_report_supported_opcodes_all *)buf;
8622	avail_len = scsi_4btoul(hdr->length);
8623	avail_len += sizeof(hdr->length);
8624	/*
8625	 * Take the lesser of the amount of data the drive claims is
8626	 * available, and the amount of data the HBA says was returned.
8627	 */
8628	avail_len = MIN(avail_len, valid_len);
8629
8630	used_len = sizeof(hdr->length);
8631
8632	printf("%-6s %4s %8s ",
8633	       "Opcode", "SA", "CDB len" );
8634
8635	if (td_req != 0)
8636		printf("%5s %6s %6s ", "CS", "Nom", "Rec");
8637	printf(" Description\n");
8638
8639	while ((avail_len - used_len) > sizeof(*desc)) {
8640		struct scsi_report_supported_opcodes_timeout *td;
8641		uint32_t td_len;
8642		const char *op_desc = NULL;
8643
8644		cur_ptr = &buf[used_len];
8645		desc = (struct scsi_report_supported_opcodes_descr *)cur_ptr;
8646
8647		op_desc = scsi_op_desc(desc->opcode, &device->inq_data);
8648		if (op_desc == NULL)
8649			op_desc = "UNKNOWN";
8650
8651		printf("0x%02x   %#4x %8u ", desc->opcode,
8652		       scsi_2btoul(desc->service_action),
8653		       scsi_2btoul(desc->cdb_length));
8654
8655		used_len += sizeof(*desc);
8656
8657		if ((desc->flags & RSO_CTDP) == 0) {
8658			printf(" %s\n", op_desc);
8659			continue;
8660		}
8661
8662		/*
8663		 * If we don't have enough space to fit a timeout
8664		 * descriptor, then we're done.
8665		 */
8666		if (avail_len - used_len < sizeof(*td)) {
8667			used_len = avail_len;
8668			printf(" %s\n", op_desc);
8669			continue;
8670		}
8671		cur_ptr = &buf[used_len];
8672		td = (struct scsi_report_supported_opcodes_timeout *)cur_ptr;
8673		td_len = scsi_2btoul(td->length);
8674		td_len += sizeof(td->length);
8675
8676		used_len += td_len;
8677		/*
8678		 * If the given timeout descriptor length is less than what
8679		 * we understand, skip it.
8680		 */
8681		if (td_len < sizeof(*td)) {
8682			printf(" %s\n", op_desc);
8683			continue;
8684		}
8685
8686		printf(" 0x%02x %6u %6u  %s\n", td->cmd_specific,
8687		       scsi_4btoul(td->nominal_time),
8688		       scsi_4btoul(td->recommended_time), op_desc);
8689	}
8690bailout:
8691	return (retval);
8692}
8693
8694static int
8695scsiopcodes(struct cam_device *device, int argc, char **argv,
8696	    char *combinedopt, int task_attr, int retry_count, int timeout,
8697	    int verbosemode)
8698{
8699	int c;
8700	uint32_t opcode = 0, service_action = 0;
8701	int td_set = 0, opcode_set = 0, sa_set = 0;
8702	int show_sa_errors = 1;
8703	uint32_t valid_len = 0;
8704	uint8_t *buf = NULL;
8705	char *endptr;
8706	int retval = 0;
8707
8708	while ((c = getopt(argc, argv, combinedopt)) != -1) {
8709		switch (c) {
8710		case 'N':
8711			show_sa_errors = 0;
8712			break;
8713		case 'o':
8714			opcode = strtoul(optarg, &endptr, 0);
8715			if (*endptr != '\0') {
8716				warnx("Invalid opcode \"%s\", must be a number",
8717				      optarg);
8718				retval = 1;
8719				goto bailout;
8720			}
8721			if (opcode > 0xff) {
8722				warnx("Invalid opcode 0x%#x, must be between"
8723				      "0 and 0xff inclusive", opcode);
8724				retval = 1;
8725				goto bailout;
8726			}
8727			opcode_set = 1;
8728			break;
8729		case 's':
8730			service_action = strtoul(optarg, &endptr, 0);
8731			if (*endptr != '\0') {
8732				warnx("Invalid service action \"%s\", must "
8733				      "be a number", optarg);
8734				retval = 1;
8735				goto bailout;
8736			}
8737			if (service_action > 0xffff) {
8738				warnx("Invalid service action 0x%#x, must "
8739				      "be between 0 and 0xffff inclusive",
8740				      service_action);
8741				retval = 1;
8742			}
8743			sa_set = 1;
8744			break;
8745		case 'T':
8746			td_set = 1;
8747			break;
8748		default:
8749			break;
8750		}
8751	}
8752
8753	if ((sa_set != 0)
8754	 && (opcode_set == 0)) {
8755		warnx("You must specify an opcode with -o if a service "
8756		      "action is given");
8757		retval = 1;
8758		goto bailout;
8759	}
8760	retval = scsigetopcodes(device, opcode_set, opcode, show_sa_errors,
8761				sa_set, service_action, td_set, task_attr,
8762				retry_count, timeout, verbosemode, &valid_len,
8763				&buf);
8764	if (retval != 0)
8765		goto bailout;
8766
8767	if ((opcode_set != 0)
8768	 || (sa_set != 0)) {
8769		retval = scsiprintoneopcode(device, opcode, sa_set,
8770					    service_action, buf, valid_len);
8771	} else {
8772		retval = scsiprintopcodes(device, td_set, buf, valid_len);
8773	}
8774
8775bailout:
8776	free(buf);
8777
8778	return (retval);
8779}
8780
8781#endif /* MINIMALISTIC */
8782
8783static int
8784scsireprobe(struct cam_device *device)
8785{
8786	union ccb *ccb;
8787	int retval = 0;
8788
8789	ccb = cam_getccb(device);
8790
8791	if (ccb == NULL) {
8792		warnx("%s: error allocating ccb", __func__);
8793		return (1);
8794	}
8795
8796	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
8797
8798	ccb->ccb_h.func_code = XPT_REPROBE_LUN;
8799
8800	if (cam_send_ccb(device, ccb) < 0) {
8801		warn("error sending XPT_REPROBE_LUN CCB");
8802		retval = 1;
8803		goto bailout;
8804	}
8805
8806	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
8807		cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
8808		retval = 1;
8809		goto bailout;
8810	}
8811
8812bailout:
8813	cam_freeccb(ccb);
8814
8815	return (retval);
8816}
8817
8818void
8819usage(int printlong)
8820{
8821
8822	fprintf(printlong ? stdout : stderr,
8823"usage:  camcontrol <command>  [device id][generic args][command args]\n"
8824"        camcontrol devlist    [-b] [-v]\n"
8825#ifndef MINIMALISTIC
8826"        camcontrol periphlist [dev_id][-n dev_name] [-u unit]\n"
8827"        camcontrol tur        [dev_id][generic args]\n"
8828"        camcontrol inquiry    [dev_id][generic args] [-D] [-S] [-R]\n"
8829"        camcontrol identify   [dev_id][generic args] [-v]\n"
8830"        camcontrol reportluns [dev_id][generic args] [-c] [-l] [-r report]\n"
8831"        camcontrol readcap    [dev_id][generic args] [-b] [-h] [-H] [-N]\n"
8832"                              [-q] [-s]\n"
8833"        camcontrol start      [dev_id][generic args]\n"
8834"        camcontrol stop       [dev_id][generic args]\n"
8835"        camcontrol load       [dev_id][generic args]\n"
8836"        camcontrol eject      [dev_id][generic args]\n"
8837"        camcontrol reprobe    [dev_id][generic args]\n"
8838#endif /* MINIMALISTIC */
8839"        camcontrol rescan     <all | bus[:target:lun] | dev_id>\n"
8840"        camcontrol reset      <all | bus[:target:lun] | dev_id>\n"
8841#ifndef MINIMALISTIC
8842"        camcontrol defects    [dev_id][generic args] <-f format> [-P][-G]\n"
8843"                              [-q][-s][-S offset][-X]\n"
8844"        camcontrol modepage   [dev_id][generic args] <-m page | -l>\n"
8845"                              [-P pagectl][-e | -b][-d]\n"
8846"        camcontrol cmd        [dev_id][generic args]\n"
8847"                              <-a cmd [args] | -c cmd [args]>\n"
8848"                              [-d] [-f] [-i len fmt|-o len fmt [args]] [-r fmt]\n"
8849"        camcontrol smpcmd     [dev_id][generic args]\n"
8850"                              <-r len fmt [args]> <-R len fmt [args]>\n"
8851"        camcontrol smprg      [dev_id][generic args][-l]\n"
8852"        camcontrol smppc      [dev_id][generic args] <-p phy> [-l]\n"
8853"                              [-o operation][-d name][-m rate][-M rate]\n"
8854"                              [-T pp_timeout][-a enable|disable]\n"
8855"                              [-A enable|disable][-s enable|disable]\n"
8856"                              [-S enable|disable]\n"
8857"        camcontrol smpphylist [dev_id][generic args][-l][-q]\n"
8858"        camcontrol smpmaninfo [dev_id][generic args][-l]\n"
8859"        camcontrol debug      [-I][-P][-T][-S][-X][-c]\n"
8860"                              <all|bus[:target[:lun]]|off>\n"
8861"        camcontrol tags       [dev_id][generic args] [-N tags] [-q] [-v]\n"
8862"        camcontrol negotiate  [dev_id][generic args] [-a][-c]\n"
8863"                              [-D <enable|disable>][-M mode][-O offset]\n"
8864"                              [-q][-R syncrate][-v][-T <enable|disable>]\n"
8865"                              [-U][-W bus_width]\n"
8866"        camcontrol format     [dev_id][generic args][-q][-r][-w][-y]\n"
8867"        camcontrol sanitize   [dev_id][generic args]\n"
8868"                              [-a overwrite|block|crypto|exitfailure]\n"
8869"                              [-c passes][-I][-P pattern][-q][-U][-r][-w]\n"
8870"                              [-y]\n"
8871"        camcontrol idle       [dev_id][generic args][-t time]\n"
8872"        camcontrol standby    [dev_id][generic args][-t time]\n"
8873"        camcontrol sleep      [dev_id][generic args]\n"
8874"        camcontrol apm        [dev_id][generic args][-l level]\n"
8875"        camcontrol aam        [dev_id][generic args][-l level]\n"
8876"        camcontrol fwdownload [dev_id][generic args] <-f fw_image> [-q]\n"
8877"                              [-s][-y]\n"
8878"        camcontrol security   [dev_id][generic args]\n"
8879"                              <-d pwd | -e pwd | -f | -h pwd | -k pwd>\n"
8880"                              [-l <high|maximum>] [-q] [-s pwd] [-T timeout]\n"
8881"                              [-U <user|master>] [-y]\n"
8882"        camcontrol hpa        [dev_id][generic args] [-f] [-l] [-P] [-p pwd]\n"
8883"                              [-q] [-s max_sectors] [-U pwd] [-y]\n"
8884"        camcontrol persist    [dev_id][generic args] <-i action|-o action>\n"
8885"                              [-a][-I tid][-k key][-K sa_key][-p][-R rtp]\n"
8886"                              [-s scope][-S][-T type][-U]\n"
8887"        camcontrol attrib     [dev_id][generic args] <-r action|-w attr>\n"
8888"                              [-a attr_num][-c][-e elem][-F form1,form1]\n"
8889"                              [-p part][-s start][-T type][-V vol]\n"
8890"        camcontrol opcodes    [dev_id][generic args][-o opcode][-s SA]\n"
8891"                              [-N][-T]\n"
8892#endif /* MINIMALISTIC */
8893"        camcontrol help\n");
8894	if (!printlong)
8895		return;
8896#ifndef MINIMALISTIC
8897	fprintf(stdout,
8898"Specify one of the following options:\n"
8899"devlist     list all CAM devices\n"
8900"periphlist  list all CAM peripheral drivers attached to a device\n"
8901"tur         send a test unit ready to the named device\n"
8902"inquiry     send a SCSI inquiry command to the named device\n"
8903"identify    send a ATA identify command to the named device\n"
8904"reportluns  send a SCSI report luns command to the device\n"
8905"readcap     send a SCSI read capacity command to the device\n"
8906"start       send a Start Unit command to the device\n"
8907"stop        send a Stop Unit command to the device\n"
8908"load        send a Start Unit command to the device with the load bit set\n"
8909"eject       send a Stop Unit command to the device with the eject bit set\n"
8910"reprobe     update capacity information of the given device\n"
8911"rescan      rescan all buses, the given bus, bus:target:lun or device\n"
8912"reset       reset all buses, the given bus, bus:target:lun or device\n"
8913"defects     read the defect list of the specified device\n"
8914"modepage    display or edit (-e) the given mode page\n"
8915"cmd         send the given SCSI command, may need -i or -o as well\n"
8916"smpcmd      send the given SMP command, requires -o and -i\n"
8917"smprg       send the SMP Report General command\n"
8918"smppc       send the SMP PHY Control command, requires -p\n"
8919"smpphylist  display phys attached to a SAS expander\n"
8920"smpmaninfo  send the SMP Report Manufacturer Info command\n"
8921"debug       turn debugging on/off for a bus, target, or lun, or all devices\n"
8922"tags        report or set the number of transaction slots for a device\n"
8923"negotiate   report or set device negotiation parameters\n"
8924"format      send the SCSI FORMAT UNIT command to the named device\n"
8925"sanitize    send the SCSI SANITIZE command to the named device\n"
8926"idle        send the ATA IDLE command to the named device\n"
8927"standby     send the ATA STANDBY command to the named device\n"
8928"sleep       send the ATA SLEEP command to the named device\n"
8929"fwdownload  program firmware of the named device with the given image\n"
8930"security    report or send ATA security commands to the named device\n"
8931"persist     send the SCSI PERSISTENT RESERVE IN or OUT commands\n"
8932"attrib      send the SCSI READ or WRITE ATTRIBUTE commands\n"
8933"opcodes     send the SCSI REPORT SUPPORTED OPCODES command\n"
8934"help        this message\n"
8935"Device Identifiers:\n"
8936"bus:target        specify the bus and target, lun defaults to 0\n"
8937"bus:target:lun    specify the bus, target and lun\n"
8938"deviceUNIT        specify the device name, like \"da4\" or \"cd2\"\n"
8939"Generic arguments:\n"
8940"-v                be verbose, print out sense information\n"
8941"-t timeout        command timeout in seconds, overrides default timeout\n"
8942"-n dev_name       specify device name, e.g. \"da\", \"cd\"\n"
8943"-u unit           specify unit number, e.g. \"0\", \"5\"\n"
8944"-E                have the kernel attempt to perform SCSI error recovery\n"
8945"-C count          specify the SCSI command retry count (needs -E to work)\n"
8946"-Q task_attr      specify ordered, simple or head tag type for SCSI cmds\n"
8947"modepage arguments:\n"
8948"-l                list all available mode pages\n"
8949"-m page           specify the mode page to view or edit\n"
8950"-e                edit the specified mode page\n"
8951"-b                force view to binary mode\n"
8952"-d                disable block descriptors for mode sense\n"
8953"-P pgctl          page control field 0-3\n"
8954"defects arguments:\n"
8955"-f format         specify defect list format (block, bfi or phys)\n"
8956"-G                get the grown defect list\n"
8957"-P                get the permanent defect list\n"
8958"inquiry arguments:\n"
8959"-D                get the standard inquiry data\n"
8960"-S                get the serial number\n"
8961"-R                get the transfer rate, etc.\n"
8962"reportluns arguments:\n"
8963"-c                only report a count of available LUNs\n"
8964"-l                only print out luns, and not a count\n"
8965"-r <reporttype>   specify \"default\", \"wellknown\" or \"all\"\n"
8966"readcap arguments\n"
8967"-b                only report the blocksize\n"
8968"-h                human readable device size, base 2\n"
8969"-H                human readable device size, base 10\n"
8970"-N                print the number of blocks instead of last block\n"
8971"-q                quiet, print numbers only\n"
8972"-s                only report the last block/device size\n"
8973"cmd arguments:\n"
8974"-c cdb [args]     specify the SCSI CDB\n"
8975"-i len fmt        specify input data and input data format\n"
8976"-o len fmt [args] specify output data and output data fmt\n"
8977"smpcmd arguments:\n"
8978"-r len fmt [args] specify the SMP command to be sent\n"
8979"-R len fmt [args] specify SMP response format\n"
8980"smprg arguments:\n"
8981"-l                specify the long response format\n"
8982"smppc arguments:\n"
8983"-p phy            specify the PHY to operate on\n"
8984"-l                specify the long request/response format\n"
8985"-o operation      specify the phy control operation\n"
8986"-d name           set the attached device name\n"
8987"-m rate           set the minimum physical link rate\n"
8988"-M rate           set the maximum physical link rate\n"
8989"-T pp_timeout     set the partial pathway timeout value\n"
8990"-a enable|disable enable or disable SATA slumber\n"
8991"-A enable|disable enable or disable SATA partial phy power\n"
8992"-s enable|disable enable or disable SAS slumber\n"
8993"-S enable|disable enable or disable SAS partial phy power\n"
8994"smpphylist arguments:\n"
8995"-l                specify the long response format\n"
8996"-q                only print phys with attached devices\n"
8997"smpmaninfo arguments:\n"
8998"-l                specify the long response format\n"
8999"debug arguments:\n"
9000"-I                CAM_DEBUG_INFO -- scsi commands, errors, data\n"
9001"-T                CAM_DEBUG_TRACE -- routine flow tracking\n"
9002"-S                CAM_DEBUG_SUBTRACE -- internal routine command flow\n"
9003"-c                CAM_DEBUG_CDB -- print out SCSI CDBs only\n"
9004"tags arguments:\n"
9005"-N tags           specify the number of tags to use for this device\n"
9006"-q                be quiet, don't report the number of tags\n"
9007"-v                report a number of tag-related parameters\n"
9008"negotiate arguments:\n"
9009"-a                send a test unit ready after negotiation\n"
9010"-c                report/set current negotiation settings\n"
9011"-D <arg>          \"enable\" or \"disable\" disconnection\n"
9012"-M mode           set ATA mode\n"
9013"-O offset         set command delay offset\n"
9014"-q                be quiet, don't report anything\n"
9015"-R syncrate       synchronization rate in MHz\n"
9016"-T <arg>          \"enable\" or \"disable\" tagged queueing\n"
9017"-U                report/set user negotiation settings\n"
9018"-W bus_width      set the bus width in bits (8, 16 or 32)\n"
9019"-v                also print a Path Inquiry CCB for the controller\n"
9020"format arguments:\n"
9021"-q                be quiet, don't print status messages\n"
9022"-r                run in report only mode\n"
9023"-w                don't send immediate format command\n"
9024"-y                don't ask any questions\n"
9025"sanitize arguments:\n"
9026"-a operation      operation mode: overwrite, block, crypto or exitfailure\n"
9027"-c passes         overwrite passes to perform (1 to 31)\n"
9028"-I                invert overwrite pattern after each pass\n"
9029"-P pattern        path to overwrite pattern file\n"
9030"-q                be quiet, don't print status messages\n"
9031"-r                run in report only mode\n"
9032"-U                run operation in unrestricted completion exit mode\n"
9033"-w                don't send immediate sanitize command\n"
9034"-y                don't ask any questions\n"
9035"idle/standby arguments:\n"
9036"-t <arg>          number of seconds before respective state.\n"
9037"fwdownload arguments:\n"
9038"-f fw_image       path to firmware image file\n"
9039"-q                don't print informational messages, only errors\n"
9040"-s                run in simulation mode\n"
9041"-v                print info for every firmware segment sent to device\n"
9042"-y                don't ask any questions\n"
9043"security arguments:\n"
9044"-d pwd            disable security using the given password for the selected\n"
9045"                  user\n"
9046"-e pwd            erase the device using the given pwd for the selected user\n"
9047"-f                freeze the security configuration of the specified device\n"
9048"-h pwd            enhanced erase the device using the given pwd for the\n"
9049"                  selected user\n"
9050"-k pwd            unlock the device using the given pwd for the selected\n"
9051"                  user\n"
9052"-l <high|maximum> specifies which security level to set: high or maximum\n"
9053"-q                be quiet, do not print any status messages\n"
9054"-s pwd            password the device (enable security) using the given\n"
9055"                  pwd for the selected user\n"
9056"-T timeout        overrides the timeout (seconds) used for erase operation\n"
9057"-U <user|master>  specifies which user to set: user or master\n"
9058"-y                don't ask any questions\n"
9059"hpa arguments:\n"
9060"-f                freeze the HPA configuration of the device\n"
9061"-l                lock the HPA configuration of the device\n"
9062"-P                make the HPA max sectors persist\n"
9063"-p pwd            Set the HPA configuration password required for unlock\n"
9064"                  calls\n"
9065"-q                be quiet, do not print any status messages\n"
9066"-s sectors        configures the maximum user accessible sectors of the\n"
9067"                  device\n"
9068"-U pwd            unlock the HPA configuration of the device\n"
9069"-y                don't ask any questions\n"
9070"persist arguments:\n"
9071"-i action         specify read_keys, read_reservation, report_cap, or\n"
9072"                  read_full_status\n"
9073"-o action         specify register, register_ignore, reserve, release,\n"
9074"                  clear, preempt, preempt_abort, register_move, replace_lost\n"
9075"-a                set the All Target Ports (ALL_TG_PT) bit\n"
9076"-I tid            specify a Transport ID, e.g.: sas,0x1234567812345678\n"
9077"-k key            specify the Reservation Key\n"
9078"-K sa_key         specify the Service Action Reservation Key\n"
9079"-p                set the Activate Persist Through Power Loss bit\n"
9080"-R rtp            specify the Relative Target Port\n"
9081"-s scope          specify the scope: lun, extent, element or a number\n"
9082"-S                specify Transport ID for register, requires -I\n"
9083"-T res_type       specify the reservation type: read_shared, wr_ex, rd_ex,\n"
9084"                  ex_ac, wr_ex_ro, ex_ac_ro, wr_ex_ar, ex_ac_ar\n"
9085"-U                unregister the current initiator for register_move\n"
9086"attrib arguments:\n"
9087"-r action         specify attr_values, attr_list, lv_list, part_list, or\n"
9088"                  supp_attr\n"
9089"-w attr           specify an attribute to write, one -w argument per attr\n"
9090"-a attr_num       only display this attribute number\n"
9091"-c                get cached attributes\n"
9092"-e elem_addr      request attributes for the given element in a changer\n"
9093"-F form1,form2    output format, comma separated list: text_esc, text_raw,\n"
9094"                  nonascii_esc, nonascii_trim, nonascii_raw, field_all,\n"
9095"                  field_none, field_desc, field_num, field_size, field_rw\n"
9096"-p partition      request attributes for the given partition\n"
9097"-s start_attr     request attributes starting at the given number\n"
9098"-T elem_type      specify the element type (used with -e)\n"
9099"-V logical_vol    specify the logical volume ID\n"
9100"opcodes arguments:\n"
9101"-o opcode         specify the individual opcode to list\n"
9102"-s service_action specify the service action for the opcode\n"
9103"-N                do not return SCSI error for unsupported SA\n"
9104"-T                request nominal and recommended timeout values\n"
9105);
9106#endif /* MINIMALISTIC */
9107}
9108
9109int
9110main(int argc, char **argv)
9111{
9112	int c;
9113	char *device = NULL;
9114	int unit = 0;
9115	struct cam_device *cam_dev = NULL;
9116	int timeout = 0, retry_count = 1;
9117	camcontrol_optret optreturn;
9118	char *tstr;
9119	const char *mainopt = "C:En:Q:t:u:v";
9120	const char *subopt = NULL;
9121	char combinedopt[256];
9122	int error = 0, optstart = 2;
9123	int task_attr = MSG_SIMPLE_Q_TAG;
9124	int devopen = 1;
9125#ifndef MINIMALISTIC
9126	path_id_t bus;
9127	target_id_t target;
9128	lun_id_t lun;
9129#endif /* MINIMALISTIC */
9130
9131	cmdlist = CAM_CMD_NONE;
9132	arglist = CAM_ARG_NONE;
9133
9134	if (argc < 2) {
9135		usage(0);
9136		exit(1);
9137	}
9138
9139	/*
9140	 * Get the base option.
9141	 */
9142	optreturn = getoption(option_table,argv[1], &cmdlist, &arglist,&subopt);
9143
9144	if (optreturn == CC_OR_AMBIGUOUS) {
9145		warnx("ambiguous option %s", argv[1]);
9146		usage(0);
9147		exit(1);
9148	} else if (optreturn == CC_OR_NOT_FOUND) {
9149		warnx("option %s not found", argv[1]);
9150		usage(0);
9151		exit(1);
9152	}
9153
9154	/*
9155	 * Ahh, getopt(3) is a pain.
9156	 *
9157	 * This is a gross hack.  There really aren't many other good
9158	 * options (excuse the pun) for parsing options in a situation like
9159	 * this.  getopt is kinda braindead, so you end up having to run
9160	 * through the options twice, and give each invocation of getopt
9161	 * the option string for the other invocation.
9162	 *
9163	 * You would think that you could just have two groups of options.
9164	 * The first group would get parsed by the first invocation of
9165	 * getopt, and the second group would get parsed by the second
9166	 * invocation of getopt.  It doesn't quite work out that way.  When
9167	 * the first invocation of getopt finishes, it leaves optind pointing
9168	 * to the argument _after_ the first argument in the second group.
9169	 * So when the second invocation of getopt comes around, it doesn't
9170	 * recognize the first argument it gets and then bails out.
9171	 *
9172	 * A nice alternative would be to have a flag for getopt that says
9173	 * "just keep parsing arguments even when you encounter an unknown
9174	 * argument", but there isn't one.  So there's no real clean way to
9175	 * easily parse two sets of arguments without having one invocation
9176	 * of getopt know about the other.
9177	 *
9178	 * Without this hack, the first invocation of getopt would work as
9179	 * long as the generic arguments are first, but the second invocation
9180	 * (in the subfunction) would fail in one of two ways.  In the case
9181	 * where you don't set optreset, it would fail because optind may be
9182	 * pointing to the argument after the one it should be pointing at.
9183	 * In the case where you do set optreset, and reset optind, it would
9184	 * fail because getopt would run into the first set of options, which
9185	 * it doesn't understand.
9186	 *
9187	 * All of this would "sort of" work if you could somehow figure out
9188	 * whether optind had been incremented one option too far.  The
9189	 * mechanics of that, however, are more daunting than just giving
9190	 * both invocations all of the expect options for either invocation.
9191	 *
9192	 * Needless to say, I wouldn't mind if someone invented a better
9193	 * (non-GPL!) command line parsing interface than getopt.  I
9194	 * wouldn't mind if someone added more knobs to getopt to make it
9195	 * work better.  Who knows, I may talk myself into doing it someday,
9196	 * if the standards weenies let me.  As it is, it just leads to
9197	 * hackery like this and causes people to avoid it in some cases.
9198	 *
9199	 * KDM, September 8th, 1998
9200	 */
9201	if (subopt != NULL)
9202		sprintf(combinedopt, "%s%s", mainopt, subopt);
9203	else
9204		sprintf(combinedopt, "%s", mainopt);
9205
9206	/*
9207	 * For these options we do not parse optional device arguments and
9208	 * we do not open a passthrough device.
9209	 */
9210	if ((cmdlist == CAM_CMD_RESCAN)
9211	 || (cmdlist == CAM_CMD_RESET)
9212	 || (cmdlist == CAM_CMD_DEVTREE)
9213	 || (cmdlist == CAM_CMD_USAGE)
9214	 || (cmdlist == CAM_CMD_DEBUG))
9215		devopen = 0;
9216
9217#ifndef MINIMALISTIC
9218	if ((devopen == 1)
9219	 && (argc > 2 && argv[2][0] != '-')) {
9220		char name[30];
9221		int rv;
9222
9223		if (isdigit(argv[2][0])) {
9224			/* device specified as bus:target[:lun] */
9225			rv = parse_btl(argv[2], &bus, &target, &lun, &arglist);
9226			if (rv < 2)
9227				errx(1, "numeric device specification must "
9228				     "be either bus:target, or "
9229				     "bus:target:lun");
9230			/* default to 0 if lun was not specified */
9231			if ((arglist & CAM_ARG_LUN) == 0) {
9232				lun = 0;
9233				arglist |= CAM_ARG_LUN;
9234			}
9235			optstart++;
9236		} else {
9237			if (cam_get_device(argv[2], name, sizeof name, &unit)
9238			    == -1)
9239				errx(1, "%s", cam_errbuf);
9240			device = strdup(name);
9241			arglist |= CAM_ARG_DEVICE | CAM_ARG_UNIT;
9242			optstart++;
9243		}
9244	}
9245#endif /* MINIMALISTIC */
9246	/*
9247	 * Start getopt processing at argv[2/3], since we've already
9248	 * accepted argv[1..2] as the command name, and as a possible
9249	 * device name.
9250	 */
9251	optind = optstart;
9252
9253	/*
9254	 * Now we run through the argument list looking for generic
9255	 * options, and ignoring options that possibly belong to
9256	 * subfunctions.
9257	 */
9258	while ((c = getopt(argc, argv, combinedopt))!= -1){
9259		switch(c) {
9260			case 'C':
9261				retry_count = strtol(optarg, NULL, 0);
9262				if (retry_count < 0)
9263					errx(1, "retry count %d is < 0",
9264					     retry_count);
9265				arglist |= CAM_ARG_RETRIES;
9266				break;
9267			case 'E':
9268				arglist |= CAM_ARG_ERR_RECOVER;
9269				break;
9270			case 'n':
9271				arglist |= CAM_ARG_DEVICE;
9272				tstr = optarg;
9273				while (isspace(*tstr) && (*tstr != '\0'))
9274					tstr++;
9275				device = (char *)strdup(tstr);
9276				break;
9277			case 'Q': {
9278				char *endptr;
9279				int table_entry = 0;
9280
9281				tstr = optarg;
9282				while (isspace(*tstr) && (*tstr != '\0'))
9283					tstr++;
9284				if (isdigit(*tstr)) {
9285					task_attr = strtol(tstr, &endptr, 0);
9286					if (*endptr != '\0') {
9287						errx(1, "Invalid queue option "
9288						    "%s", tstr);
9289					}
9290				} else {
9291					size_t table_size;
9292					scsi_nv_status status;
9293
9294					table_size = sizeof(task_attrs) /
9295						     sizeof(task_attrs[0]);
9296					status = scsi_get_nv(task_attrs,
9297					    table_size, tstr, &table_entry,
9298					    SCSI_NV_FLAG_IG_CASE);
9299					if (status == SCSI_NV_FOUND)
9300						task_attr = task_attrs[
9301						    table_entry].value;
9302					else {
9303						errx(1, "%s option %s",
9304						  (status == SCSI_NV_AMBIGUOUS)?
9305						    "ambiguous" : "invalid",
9306						    tstr);
9307					}
9308				}
9309				break;
9310			}
9311			case 't':
9312				timeout = strtol(optarg, NULL, 0);
9313				if (timeout < 0)
9314					errx(1, "invalid timeout %d", timeout);
9315				/* Convert the timeout from seconds to ms */
9316				timeout *= 1000;
9317				arglist |= CAM_ARG_TIMEOUT;
9318				break;
9319			case 'u':
9320				arglist |= CAM_ARG_UNIT;
9321				unit = strtol(optarg, NULL, 0);
9322				break;
9323			case 'v':
9324				arglist |= CAM_ARG_VERBOSE;
9325				break;
9326			default:
9327				break;
9328		}
9329	}
9330
9331#ifndef MINIMALISTIC
9332	/*
9333	 * For most commands we'll want to open the passthrough device
9334	 * associated with the specified device.  In the case of the rescan
9335	 * commands, we don't use a passthrough device at all, just the
9336	 * transport layer device.
9337	 */
9338	if (devopen == 1) {
9339		if (((arglist & (CAM_ARG_BUS|CAM_ARG_TARGET)) == 0)
9340		 && (((arglist & CAM_ARG_DEVICE) == 0)
9341		  || ((arglist & CAM_ARG_UNIT) == 0))) {
9342			errx(1, "subcommand \"%s\" requires a valid device "
9343			     "identifier", argv[1]);
9344		}
9345
9346		if ((cam_dev = ((arglist & (CAM_ARG_BUS | CAM_ARG_TARGET))?
9347				cam_open_btl(bus, target, lun, O_RDWR, NULL) :
9348				cam_open_spec_device(device,unit,O_RDWR,NULL)))
9349		     == NULL)
9350			errx(1,"%s", cam_errbuf);
9351	}
9352#endif /* MINIMALISTIC */
9353
9354	/*
9355	 * Reset optind to 2, and reset getopt, so these routines can parse
9356	 * the arguments again.
9357	 */
9358	optind = optstart;
9359	optreset = 1;
9360
9361	switch(cmdlist) {
9362#ifndef MINIMALISTIC
9363		case CAM_CMD_DEVLIST:
9364			error = getdevlist(cam_dev);
9365			break;
9366		case CAM_CMD_HPA:
9367			error = atahpa(cam_dev, retry_count, timeout,
9368				       argc, argv, combinedopt);
9369			break;
9370#endif /* MINIMALISTIC */
9371		case CAM_CMD_DEVTREE:
9372			error = getdevtree(argc, argv, combinedopt);
9373			break;
9374#ifndef MINIMALISTIC
9375		case CAM_CMD_TUR:
9376			error = testunitready(cam_dev, task_attr, retry_count,
9377			    timeout, 0);
9378			break;
9379		case CAM_CMD_INQUIRY:
9380			error = scsidoinquiry(cam_dev, argc, argv, combinedopt,
9381					      task_attr, retry_count, timeout);
9382			break;
9383		case CAM_CMD_IDENTIFY:
9384			error = ataidentify(cam_dev, retry_count, timeout);
9385			break;
9386		case CAM_CMD_STARTSTOP:
9387			error = scsistart(cam_dev, arglist & CAM_ARG_START_UNIT,
9388					  arglist & CAM_ARG_EJECT, task_attr,
9389					  retry_count, timeout);
9390			break;
9391#endif /* MINIMALISTIC */
9392		case CAM_CMD_RESCAN:
9393			error = dorescan_or_reset(argc, argv, 1);
9394			break;
9395		case CAM_CMD_RESET:
9396			error = dorescan_or_reset(argc, argv, 0);
9397			break;
9398#ifndef MINIMALISTIC
9399		case CAM_CMD_READ_DEFECTS:
9400			error = readdefects(cam_dev, argc, argv, combinedopt,
9401					    task_attr, retry_count, timeout);
9402			break;
9403		case CAM_CMD_MODE_PAGE:
9404			modepage(cam_dev, argc, argv, combinedopt,
9405				 task_attr, retry_count, timeout);
9406			break;
9407		case CAM_CMD_SCSI_CMD:
9408			error = scsicmd(cam_dev, argc, argv, combinedopt,
9409					task_attr, retry_count, timeout);
9410			break;
9411		case CAM_CMD_SMP_CMD:
9412			error = smpcmd(cam_dev, argc, argv, combinedopt,
9413				       retry_count, timeout);
9414			break;
9415		case CAM_CMD_SMP_RG:
9416			error = smpreportgeneral(cam_dev, argc, argv,
9417						 combinedopt, retry_count,
9418						 timeout);
9419			break;
9420		case CAM_CMD_SMP_PC:
9421			error = smpphycontrol(cam_dev, argc, argv, combinedopt,
9422					      retry_count, timeout);
9423			break;
9424		case CAM_CMD_SMP_PHYLIST:
9425			error = smpphylist(cam_dev, argc, argv, combinedopt,
9426					   retry_count, timeout);
9427			break;
9428		case CAM_CMD_SMP_MANINFO:
9429			error = smpmaninfo(cam_dev, argc, argv, combinedopt,
9430					   retry_count, timeout);
9431			break;
9432		case CAM_CMD_DEBUG:
9433			error = camdebug(argc, argv, combinedopt);
9434			break;
9435		case CAM_CMD_TAG:
9436			error = tagcontrol(cam_dev, argc, argv, combinedopt);
9437			break;
9438		case CAM_CMD_RATE:
9439			error = ratecontrol(cam_dev, task_attr, retry_count,
9440					    timeout, argc, argv, combinedopt);
9441			break;
9442		case CAM_CMD_FORMAT:
9443			error = scsiformat(cam_dev, argc, argv,
9444					   combinedopt, task_attr, retry_count,
9445					   timeout);
9446			break;
9447		case CAM_CMD_REPORTLUNS:
9448			error = scsireportluns(cam_dev, argc, argv,
9449					       combinedopt, task_attr,
9450					       retry_count, timeout);
9451			break;
9452		case CAM_CMD_READCAP:
9453			error = scsireadcapacity(cam_dev, argc, argv,
9454						 combinedopt, task_attr,
9455						 retry_count, timeout);
9456			break;
9457		case CAM_CMD_IDLE:
9458		case CAM_CMD_STANDBY:
9459		case CAM_CMD_SLEEP:
9460			error = atapm(cam_dev, argc, argv,
9461				      combinedopt, retry_count, timeout);
9462			break;
9463		case CAM_CMD_APM:
9464		case CAM_CMD_AAM:
9465			error = ataaxm(cam_dev, argc, argv,
9466				      combinedopt, retry_count, timeout);
9467			break;
9468		case CAM_CMD_SECURITY:
9469			error = atasecurity(cam_dev, retry_count, timeout,
9470					    argc, argv, combinedopt);
9471			break;
9472		case CAM_CMD_DOWNLOAD_FW:
9473			error = fwdownload(cam_dev, argc, argv, combinedopt,
9474			    arglist & CAM_ARG_VERBOSE, task_attr, retry_count,
9475			    timeout);
9476			break;
9477		case CAM_CMD_SANITIZE:
9478			error = scsisanitize(cam_dev, argc, argv,
9479					     combinedopt, task_attr,
9480					     retry_count, timeout);
9481			break;
9482		case CAM_CMD_PERSIST:
9483			error = scsipersist(cam_dev, argc, argv, combinedopt,
9484			    task_attr, retry_count, timeout,
9485			    arglist & CAM_ARG_VERBOSE,
9486			    arglist & CAM_ARG_ERR_RECOVER);
9487			break;
9488		case CAM_CMD_ATTRIB:
9489			error = scsiattrib(cam_dev, argc, argv, combinedopt,
9490			    task_attr, retry_count, timeout,
9491			    arglist & CAM_ARG_VERBOSE,
9492			    arglist & CAM_ARG_ERR_RECOVER);
9493			break;
9494		case CAM_CMD_OPCODES:
9495			error = scsiopcodes(cam_dev, argc, argv, combinedopt,
9496			    task_attr, retry_count, timeout,
9497			    arglist & CAM_ARG_VERBOSE);
9498			break;
9499		case CAM_CMD_REPROBE:
9500			error = scsireprobe(cam_dev);
9501			break;
9502
9503#endif /* MINIMALISTIC */
9504		case CAM_CMD_USAGE:
9505			usage(1);
9506			break;
9507		default:
9508			usage(0);
9509			error = 1;
9510			break;
9511	}
9512
9513	if (cam_dev != NULL)
9514		cam_close_device(cam_dev);
9515
9516	exit(error);
9517}
9518