camcontrol.c revision 254954
1/*
2 * Copyright (c) 1997-2007 Kenneth D. Merry
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 *    derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/sbin/camcontrol/camcontrol.c 254954 2013-08-27 06:50:46Z mav $");
31
32#include <sys/ioctl.h>
33#include <sys/stdint.h>
34#include <sys/types.h>
35#include <sys/endian.h>
36#include <sys/sbuf.h>
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <unistd.h>
42#include <inttypes.h>
43#include <limits.h>
44#include <fcntl.h>
45#include <ctype.h>
46#include <err.h>
47#include <libutil.h>
48#ifndef MINIMALISTIC
49#include <limits.h>
50#include <inttypes.h>
51#endif
52
53#include <cam/cam.h>
54#include <cam/cam_debug.h>
55#include <cam/cam_ccb.h>
56#include <cam/scsi/scsi_all.h>
57#include <cam/scsi/scsi_da.h>
58#include <cam/scsi/scsi_pass.h>
59#include <cam/scsi/scsi_message.h>
60#include <cam/scsi/smp_all.h>
61#include <cam/ata/ata_all.h>
62#include <camlib.h>
63#include "camcontrol.h"
64
65typedef enum {
66	CAM_CMD_NONE		= 0x00000000,
67	CAM_CMD_DEVLIST		= 0x00000001,
68	CAM_CMD_TUR		= 0x00000002,
69	CAM_CMD_INQUIRY		= 0x00000003,
70	CAM_CMD_STARTSTOP	= 0x00000004,
71	CAM_CMD_RESCAN		= 0x00000005,
72	CAM_CMD_READ_DEFECTS	= 0x00000006,
73	CAM_CMD_MODE_PAGE	= 0x00000007,
74	CAM_CMD_SCSI_CMD	= 0x00000008,
75	CAM_CMD_DEVTREE		= 0x00000009,
76	CAM_CMD_USAGE		= 0x0000000a,
77	CAM_CMD_DEBUG		= 0x0000000b,
78	CAM_CMD_RESET		= 0x0000000c,
79	CAM_CMD_FORMAT		= 0x0000000d,
80	CAM_CMD_TAG		= 0x0000000e,
81	CAM_CMD_RATE		= 0x0000000f,
82	CAM_CMD_DETACH		= 0x00000010,
83	CAM_CMD_REPORTLUNS	= 0x00000011,
84	CAM_CMD_READCAP		= 0x00000012,
85	CAM_CMD_IDENTIFY	= 0x00000013,
86	CAM_CMD_IDLE		= 0x00000014,
87	CAM_CMD_STANDBY		= 0x00000015,
88	CAM_CMD_SLEEP		= 0x00000016,
89	CAM_CMD_SMP_CMD		= 0x00000017,
90	CAM_CMD_SMP_RG		= 0x00000018,
91	CAM_CMD_SMP_PC		= 0x00000019,
92	CAM_CMD_SMP_PHYLIST	= 0x0000001a,
93	CAM_CMD_SMP_MANINFO	= 0x0000001b,
94	CAM_CMD_DOWNLOAD_FW	= 0x0000001c,
95	CAM_CMD_SECURITY	= 0x0000001d,
96	CAM_CMD_HPA		= 0x0000001e
97} cam_cmdmask;
98
99typedef enum {
100	CAM_ARG_NONE		= 0x00000000,
101	CAM_ARG_VERBOSE		= 0x00000001,
102	CAM_ARG_DEVICE		= 0x00000002,
103	CAM_ARG_BUS		= 0x00000004,
104	CAM_ARG_TARGET		= 0x00000008,
105	CAM_ARG_LUN		= 0x00000010,
106	CAM_ARG_EJECT		= 0x00000020,
107	CAM_ARG_UNIT		= 0x00000040,
108	CAM_ARG_FORMAT_BLOCK	= 0x00000080,
109	CAM_ARG_FORMAT_BFI	= 0x00000100,
110	CAM_ARG_FORMAT_PHYS	= 0x00000200,
111	CAM_ARG_PLIST		= 0x00000400,
112	CAM_ARG_GLIST		= 0x00000800,
113	CAM_ARG_GET_SERIAL	= 0x00001000,
114	CAM_ARG_GET_STDINQ	= 0x00002000,
115	CAM_ARG_GET_XFERRATE	= 0x00004000,
116	CAM_ARG_INQ_MASK	= 0x00007000,
117	CAM_ARG_MODE_EDIT	= 0x00008000,
118	CAM_ARG_PAGE_CNTL	= 0x00010000,
119	CAM_ARG_TIMEOUT		= 0x00020000,
120	CAM_ARG_CMD_IN		= 0x00040000,
121	CAM_ARG_CMD_OUT		= 0x00080000,
122	CAM_ARG_DBD		= 0x00100000,
123	CAM_ARG_ERR_RECOVER	= 0x00200000,
124	CAM_ARG_RETRIES		= 0x00400000,
125	CAM_ARG_START_UNIT	= 0x00800000,
126	CAM_ARG_DEBUG_INFO	= 0x01000000,
127	CAM_ARG_DEBUG_TRACE	= 0x02000000,
128	CAM_ARG_DEBUG_SUBTRACE	= 0x04000000,
129	CAM_ARG_DEBUG_CDB	= 0x08000000,
130	CAM_ARG_DEBUG_XPT	= 0x10000000,
131	CAM_ARG_DEBUG_PERIPH	= 0x20000000,
132	CAM_ARG_DEBUG_PROBE	= 0x40000000,
133} cam_argmask;
134
135struct camcontrol_opts {
136	const char	*optname;
137	uint32_t	cmdnum;
138	cam_argmask	argnum;
139	const char	*subopt;
140};
141
142#ifndef MINIMALISTIC
143struct ata_res_pass16 {
144	u_int16_t reserved[5];
145	u_int8_t flags;
146	u_int8_t error;
147	u_int8_t sector_count_exp;
148	u_int8_t sector_count;
149	u_int8_t lba_low_exp;
150	u_int8_t lba_low;
151	u_int8_t lba_mid_exp;
152	u_int8_t lba_mid;
153	u_int8_t lba_high_exp;
154	u_int8_t lba_high;
155	u_int8_t device;
156	u_int8_t status;
157};
158
159struct ata_set_max_pwd
160{
161	u_int16_t reserved1;
162	u_int8_t password[32];
163	u_int16_t reserved2[239];
164};
165
166static const char scsicmd_opts[] = "a:c:dfi:o:r";
167static const char readdefect_opts[] = "f:GP";
168static const char negotiate_opts[] = "acD:M:O:qR:T:UW:";
169static const char smprg_opts[] = "l";
170static const char smppc_opts[] = "a:A:d:lm:M:o:p:s:S:T:";
171static const char smpphylist_opts[] = "lq";
172static char pwd_opt;
173#endif
174
175static struct camcontrol_opts option_table[] = {
176#ifndef MINIMALISTIC
177	{"tur", CAM_CMD_TUR, CAM_ARG_NONE, NULL},
178	{"inquiry", CAM_CMD_INQUIRY, CAM_ARG_NONE, "DSR"},
179	{"identify", CAM_CMD_IDENTIFY, CAM_ARG_NONE, NULL},
180	{"start", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT, NULL},
181	{"stop", CAM_CMD_STARTSTOP, CAM_ARG_NONE, NULL},
182	{"load", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT | CAM_ARG_EJECT, NULL},
183	{"eject", CAM_CMD_STARTSTOP, CAM_ARG_EJECT, NULL},
184	{"reportluns", CAM_CMD_REPORTLUNS, CAM_ARG_NONE, "clr:"},
185	{"readcapacity", CAM_CMD_READCAP, CAM_ARG_NONE, "bhHNqs"},
186#endif /* MINIMALISTIC */
187	{"rescan", CAM_CMD_RESCAN, CAM_ARG_NONE, NULL},
188	{"reset", CAM_CMD_RESET, CAM_ARG_NONE, NULL},
189#ifndef MINIMALISTIC
190	{"cmd", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts},
191	{"command", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts},
192	{"smpcmd", CAM_CMD_SMP_CMD, CAM_ARG_NONE, "r:R:"},
193	{"smprg", CAM_CMD_SMP_RG, CAM_ARG_NONE, smprg_opts},
194	{"smpreportgeneral", CAM_CMD_SMP_RG, CAM_ARG_NONE, smprg_opts},
195	{"smppc", CAM_CMD_SMP_PC, CAM_ARG_NONE, smppc_opts},
196	{"smpphycontrol", CAM_CMD_SMP_PC, CAM_ARG_NONE, smppc_opts},
197	{"smpplist", CAM_CMD_SMP_PHYLIST, CAM_ARG_NONE, smpphylist_opts},
198	{"smpphylist", CAM_CMD_SMP_PHYLIST, CAM_ARG_NONE, smpphylist_opts},
199	{"smpmaninfo", CAM_CMD_SMP_MANINFO, CAM_ARG_NONE, "l"},
200	{"defects", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts},
201	{"defectlist", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts},
202#endif /* MINIMALISTIC */
203	{"devlist", CAM_CMD_DEVTREE, CAM_ARG_NONE, NULL},
204#ifndef MINIMALISTIC
205	{"periphlist", CAM_CMD_DEVLIST, CAM_ARG_NONE, NULL},
206	{"modepage", CAM_CMD_MODE_PAGE, CAM_ARG_NONE, "bdelm:P:"},
207	{"tags", CAM_CMD_TAG, CAM_ARG_NONE, "N:q"},
208	{"negotiate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts},
209	{"rate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts},
210	{"debug", CAM_CMD_DEBUG, CAM_ARG_NONE, "IPTSXcp"},
211	{"format", CAM_CMD_FORMAT, CAM_ARG_NONE, "qrwy"},
212	{"idle", CAM_CMD_IDLE, CAM_ARG_NONE, "t:"},
213	{"standby", CAM_CMD_STANDBY, CAM_ARG_NONE, "t:"},
214	{"sleep", CAM_CMD_SLEEP, CAM_ARG_NONE, ""},
215	{"fwdownload", CAM_CMD_DOWNLOAD_FW, CAM_ARG_NONE, "f:ys"},
216	{"security", CAM_CMD_SECURITY, CAM_ARG_NONE, "d:e:fh:k:l:qs:T:U:y"},
217	{"hpa", CAM_CMD_HPA, CAM_ARG_NONE, "Pflp:qs:U:y"},
218#endif /* MINIMALISTIC */
219	{"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
220	{"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
221	{"-h", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
222	{NULL, 0, 0, NULL}
223};
224
225typedef enum {
226	CC_OR_NOT_FOUND,
227	CC_OR_AMBIGUOUS,
228	CC_OR_FOUND
229} camcontrol_optret;
230
231struct cam_devitem {
232	struct device_match_result dev_match;
233	int num_periphs;
234	struct periph_match_result *periph_matches;
235	struct scsi_vpd_device_id *device_id;
236	int device_id_len;
237	STAILQ_ENTRY(cam_devitem) links;
238};
239
240struct cam_devlist {
241	STAILQ_HEAD(, cam_devitem) dev_queue;
242	path_id_t path_id;
243};
244
245static cam_cmdmask cmdlist;
246static cam_argmask arglist;
247
248camcontrol_optret getoption(struct camcontrol_opts *table, char *arg,
249			    uint32_t *cmdnum, cam_argmask *argnum,
250			    const char **subopt);
251#ifndef MINIMALISTIC
252static int getdevlist(struct cam_device *device);
253#endif /* MINIMALISTIC */
254static int getdevtree(void);
255#ifndef MINIMALISTIC
256static int testunitready(struct cam_device *device, int retry_count,
257			 int timeout, int quiet);
258static int scsistart(struct cam_device *device, int startstop, int loadeject,
259		     int retry_count, int timeout);
260static int scsiinquiry(struct cam_device *device, int retry_count, int timeout);
261static int scsiserial(struct cam_device *device, int retry_count, int timeout);
262static int camxferrate(struct cam_device *device);
263#endif /* MINIMALISTIC */
264static int parse_btl(char *tstr, int *bus, int *target, int *lun,
265		     cam_argmask *arglst);
266static int dorescan_or_reset(int argc, char **argv, int rescan);
267static int rescan_or_reset_bus(int bus, int rescan);
268static int scanlun_or_reset_dev(int bus, int target, int lun, int scan);
269#ifndef MINIMALISTIC
270static int readdefects(struct cam_device *device, int argc, char **argv,
271		       char *combinedopt, int retry_count, int timeout);
272static void modepage(struct cam_device *device, int argc, char **argv,
273		     char *combinedopt, int retry_count, int timeout);
274static int scsicmd(struct cam_device *device, int argc, char **argv,
275		   char *combinedopt, int retry_count, int timeout);
276static int smpcmd(struct cam_device *device, int argc, char **argv,
277		  char *combinedopt, int retry_count, int timeout);
278static int smpreportgeneral(struct cam_device *device, int argc, char **argv,
279			    char *combinedopt, int retry_count, int timeout);
280static int smpphycontrol(struct cam_device *device, int argc, char **argv,
281			 char *combinedopt, int retry_count, int timeout);
282static int smpmaninfo(struct cam_device *device, int argc, char **argv,
283		      char *combinedopt, int retry_count, int timeout);
284static int getdevid(struct cam_devitem *item);
285static int buildbusdevlist(struct cam_devlist *devlist);
286static void freebusdevlist(struct cam_devlist *devlist);
287static struct cam_devitem *findsasdevice(struct cam_devlist *devlist,
288					 uint64_t sasaddr);
289static int smpphylist(struct cam_device *device, int argc, char **argv,
290		      char *combinedopt, int retry_count, int timeout);
291static int tagcontrol(struct cam_device *device, int argc, char **argv,
292		      char *combinedopt);
293static void cts_print(struct cam_device *device,
294		      struct ccb_trans_settings *cts);
295static void cpi_print(struct ccb_pathinq *cpi);
296static int get_cpi(struct cam_device *device, struct ccb_pathinq *cpi);
297static int get_cgd(struct cam_device *device, struct ccb_getdev *cgd);
298static int get_print_cts(struct cam_device *device, int user_settings,
299			 int quiet, struct ccb_trans_settings *cts);
300static int ratecontrol(struct cam_device *device, int retry_count,
301		       int timeout, int argc, char **argv, char *combinedopt);
302static int scsiformat(struct cam_device *device, int argc, char **argv,
303		      char *combinedopt, int retry_count, int timeout);
304static int scsireportluns(struct cam_device *device, int argc, char **argv,
305			  char *combinedopt, int retry_count, int timeout);
306static int scsireadcapacity(struct cam_device *device, int argc, char **argv,
307			    char *combinedopt, int retry_count, int timeout);
308static int atapm(struct cam_device *device, int argc, char **argv,
309		 char *combinedopt, int retry_count, int timeout);
310static int atasecurity(struct cam_device *device, int retry_count, int timeout,
311		       int argc, char **argv, char *combinedopt);
312static int atahpa(struct cam_device *device, int retry_count, int timeout,
313		  int argc, char **argv, char *combinedopt);
314
315#endif /* MINIMALISTIC */
316#ifndef min
317#define min(a,b) (((a)<(b))?(a):(b))
318#endif
319#ifndef max
320#define max(a,b) (((a)>(b))?(a):(b))
321#endif
322
323camcontrol_optret
324getoption(struct camcontrol_opts *table, char *arg, uint32_t *cmdnum,
325	  cam_argmask *argnum, const char **subopt)
326{
327	struct camcontrol_opts *opts;
328	int num_matches = 0;
329
330	for (opts = table; (opts != NULL) && (opts->optname != NULL);
331	     opts++) {
332		if (strncmp(opts->optname, arg, strlen(arg)) == 0) {
333			*cmdnum = opts->cmdnum;
334			*argnum = opts->argnum;
335			*subopt = opts->subopt;
336			if (++num_matches > 1)
337				return(CC_OR_AMBIGUOUS);
338		}
339	}
340
341	if (num_matches > 0)
342		return(CC_OR_FOUND);
343	else
344		return(CC_OR_NOT_FOUND);
345}
346
347#ifndef MINIMALISTIC
348static int
349getdevlist(struct cam_device *device)
350{
351	union ccb *ccb;
352	char status[32];
353	int error = 0;
354
355	ccb = cam_getccb(device);
356
357	ccb->ccb_h.func_code = XPT_GDEVLIST;
358	ccb->ccb_h.flags = CAM_DIR_NONE;
359	ccb->ccb_h.retry_count = 1;
360	ccb->cgdl.index = 0;
361	ccb->cgdl.status = CAM_GDEVLIST_MORE_DEVS;
362	while (ccb->cgdl.status == CAM_GDEVLIST_MORE_DEVS) {
363		if (cam_send_ccb(device, ccb) < 0) {
364			perror("error getting device list");
365			cam_freeccb(ccb);
366			return(1);
367		}
368
369		status[0] = '\0';
370
371		switch (ccb->cgdl.status) {
372			case CAM_GDEVLIST_MORE_DEVS:
373				strcpy(status, "MORE");
374				break;
375			case CAM_GDEVLIST_LAST_DEVICE:
376				strcpy(status, "LAST");
377				break;
378			case CAM_GDEVLIST_LIST_CHANGED:
379				strcpy(status, "CHANGED");
380				break;
381			case CAM_GDEVLIST_ERROR:
382				strcpy(status, "ERROR");
383				error = 1;
384				break;
385		}
386
387		fprintf(stdout, "%s%d:  generation: %d index: %d status: %s\n",
388			ccb->cgdl.periph_name,
389			ccb->cgdl.unit_number,
390			ccb->cgdl.generation,
391			ccb->cgdl.index,
392			status);
393
394		/*
395		 * If the list has changed, we need to start over from the
396		 * beginning.
397		 */
398		if (ccb->cgdl.status == CAM_GDEVLIST_LIST_CHANGED)
399			ccb->cgdl.index = 0;
400	}
401
402	cam_freeccb(ccb);
403
404	return(error);
405}
406#endif /* MINIMALISTIC */
407
408static int
409getdevtree(void)
410{
411	union ccb ccb;
412	int bufsize, fd;
413	unsigned int i;
414	int need_close = 0;
415	int error = 0;
416	int skip_device = 0;
417
418	if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
419		warn("couldn't open %s", XPT_DEVICE);
420		return(1);
421	}
422
423	bzero(&ccb, sizeof(union ccb));
424
425	ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
426	ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
427	ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
428
429	ccb.ccb_h.func_code = XPT_DEV_MATCH;
430	bufsize = sizeof(struct dev_match_result) * 100;
431	ccb.cdm.match_buf_len = bufsize;
432	ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
433	if (ccb.cdm.matches == NULL) {
434		warnx("can't malloc memory for matches");
435		close(fd);
436		return(1);
437	}
438	ccb.cdm.num_matches = 0;
439
440	/*
441	 * We fetch all nodes, since we display most of them in the default
442	 * case, and all in the verbose case.
443	 */
444	ccb.cdm.num_patterns = 0;
445	ccb.cdm.pattern_buf_len = 0;
446
447	/*
448	 * We do the ioctl multiple times if necessary, in case there are
449	 * more than 100 nodes in the EDT.
450	 */
451	do {
452		if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
453			warn("error sending CAMIOCOMMAND ioctl");
454			error = 1;
455			break;
456		}
457
458		if ((ccb.ccb_h.status != CAM_REQ_CMP)
459		 || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
460		    && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
461			warnx("got CAM error %#x, CDM error %d\n",
462			      ccb.ccb_h.status, ccb.cdm.status);
463			error = 1;
464			break;
465		}
466
467		for (i = 0; i < ccb.cdm.num_matches; i++) {
468			switch (ccb.cdm.matches[i].type) {
469			case DEV_MATCH_BUS: {
470				struct bus_match_result *bus_result;
471
472				/*
473				 * Only print the bus information if the
474				 * user turns on the verbose flag.
475				 */
476				if ((arglist & CAM_ARG_VERBOSE) == 0)
477					break;
478
479				bus_result =
480					&ccb.cdm.matches[i].result.bus_result;
481
482				if (need_close) {
483					fprintf(stdout, ")\n");
484					need_close = 0;
485				}
486
487				fprintf(stdout, "scbus%d on %s%d bus %d:\n",
488					bus_result->path_id,
489					bus_result->dev_name,
490					bus_result->unit_number,
491					bus_result->bus_id);
492				break;
493			}
494			case DEV_MATCH_DEVICE: {
495				struct device_match_result *dev_result;
496				char vendor[16], product[48], revision[16];
497				char fw[5], tmpstr[256];
498
499				dev_result =
500				     &ccb.cdm.matches[i].result.device_result;
501
502				if ((dev_result->flags
503				     & DEV_RESULT_UNCONFIGURED)
504				 && ((arglist & CAM_ARG_VERBOSE) == 0)) {
505					skip_device = 1;
506					break;
507				} else
508					skip_device = 0;
509
510				if (dev_result->protocol == PROTO_SCSI) {
511				    cam_strvis(vendor, dev_result->inq_data.vendor,
512					   sizeof(dev_result->inq_data.vendor),
513					   sizeof(vendor));
514				    cam_strvis(product,
515					   dev_result->inq_data.product,
516					   sizeof(dev_result->inq_data.product),
517					   sizeof(product));
518				    cam_strvis(revision,
519					   dev_result->inq_data.revision,
520					  sizeof(dev_result->inq_data.revision),
521					   sizeof(revision));
522				    sprintf(tmpstr, "<%s %s %s>", vendor, product,
523					revision);
524				} else if (dev_result->protocol == PROTO_ATA ||
525				    dev_result->protocol == PROTO_SATAPM) {
526				    cam_strvis(product,
527					   dev_result->ident_data.model,
528					   sizeof(dev_result->ident_data.model),
529					   sizeof(product));
530				    cam_strvis(revision,
531					   dev_result->ident_data.revision,
532					  sizeof(dev_result->ident_data.revision),
533					   sizeof(revision));
534				    sprintf(tmpstr, "<%s %s>", product,
535					revision);
536				} else if (dev_result->protocol == PROTO_SEMB) {
537					struct sep_identify_data *sid;
538
539					sid = (struct sep_identify_data *)
540					    &dev_result->ident_data;
541					cam_strvis(vendor, sid->vendor_id,
542					    sizeof(sid->vendor_id),
543					    sizeof(vendor));
544					cam_strvis(product, sid->product_id,
545					    sizeof(sid->product_id),
546					    sizeof(product));
547					cam_strvis(revision, sid->product_rev,
548					    sizeof(sid->product_rev),
549					    sizeof(revision));
550					cam_strvis(fw, sid->firmware_rev,
551					    sizeof(sid->firmware_rev),
552					    sizeof(fw));
553					sprintf(tmpstr, "<%s %s %s %s>",
554					    vendor, product, revision, fw);
555				} else {
556				    sprintf(tmpstr, "<>");
557				}
558				if (need_close) {
559					fprintf(stdout, ")\n");
560					need_close = 0;
561				}
562
563				fprintf(stdout, "%-33s  at scbus%d "
564					"target %d lun %d (",
565					tmpstr,
566					dev_result->path_id,
567					dev_result->target_id,
568					dev_result->target_lun);
569
570				need_close = 1;
571
572				break;
573			}
574			case DEV_MATCH_PERIPH: {
575				struct periph_match_result *periph_result;
576
577				periph_result =
578				      &ccb.cdm.matches[i].result.periph_result;
579
580				if (skip_device != 0)
581					break;
582
583				if (need_close > 1)
584					fprintf(stdout, ",");
585
586				fprintf(stdout, "%s%d",
587					periph_result->periph_name,
588					periph_result->unit_number);
589
590				need_close++;
591				break;
592			}
593			default:
594				fprintf(stdout, "unknown match type\n");
595				break;
596			}
597		}
598
599	} while ((ccb.ccb_h.status == CAM_REQ_CMP)
600		&& (ccb.cdm.status == CAM_DEV_MATCH_MORE));
601
602	if (need_close)
603		fprintf(stdout, ")\n");
604
605	close(fd);
606
607	return(error);
608}
609
610#ifndef MINIMALISTIC
611static int
612testunitready(struct cam_device *device, int retry_count, int timeout,
613	      int quiet)
614{
615	int error = 0;
616	union ccb *ccb;
617
618	ccb = cam_getccb(device);
619
620	scsi_test_unit_ready(&ccb->csio,
621			     /* retries */ retry_count,
622			     /* cbfcnp */ NULL,
623			     /* tag_action */ MSG_SIMPLE_Q_TAG,
624			     /* sense_len */ SSD_FULL_SIZE,
625			     /* timeout */ timeout ? timeout : 5000);
626
627	/* Disable freezing the device queue */
628	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
629
630	if (arglist & CAM_ARG_ERR_RECOVER)
631		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
632
633	if (cam_send_ccb(device, ccb) < 0) {
634		if (quiet == 0)
635			perror("error sending test unit ready");
636
637		if (arglist & CAM_ARG_VERBOSE) {
638			cam_error_print(device, ccb, CAM_ESF_ALL,
639					CAM_EPF_ALL, stderr);
640		}
641
642		cam_freeccb(ccb);
643		return(1);
644	}
645
646	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
647		if (quiet == 0)
648			fprintf(stdout, "Unit is ready\n");
649	} else {
650		if (quiet == 0)
651			fprintf(stdout, "Unit is not ready\n");
652		error = 1;
653
654		if (arglist & CAM_ARG_VERBOSE) {
655			cam_error_print(device, ccb, CAM_ESF_ALL,
656					CAM_EPF_ALL, stderr);
657		}
658	}
659
660	cam_freeccb(ccb);
661
662	return(error);
663}
664
665static int
666scsistart(struct cam_device *device, int startstop, int loadeject,
667	  int retry_count, int timeout)
668{
669	union ccb *ccb;
670	int error = 0;
671
672	ccb = cam_getccb(device);
673
674	/*
675	 * If we're stopping, send an ordered tag so the drive in question
676	 * will finish any previously queued writes before stopping.  If
677	 * the device isn't capable of tagged queueing, or if tagged
678	 * queueing is turned off, the tag action is a no-op.
679	 */
680	scsi_start_stop(&ccb->csio,
681			/* retries */ retry_count,
682			/* cbfcnp */ NULL,
683			/* tag_action */ startstop ? MSG_SIMPLE_Q_TAG :
684						     MSG_ORDERED_Q_TAG,
685			/* start/stop */ startstop,
686			/* load_eject */ loadeject,
687			/* immediate */ 0,
688			/* sense_len */ SSD_FULL_SIZE,
689			/* timeout */ timeout ? timeout : 120000);
690
691	/* Disable freezing the device queue */
692	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
693
694	if (arglist & CAM_ARG_ERR_RECOVER)
695		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
696
697	if (cam_send_ccb(device, ccb) < 0) {
698		perror("error sending start unit");
699
700		if (arglist & CAM_ARG_VERBOSE) {
701			cam_error_print(device, ccb, CAM_ESF_ALL,
702					CAM_EPF_ALL, stderr);
703		}
704
705		cam_freeccb(ccb);
706		return(1);
707	}
708
709	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
710		if (startstop) {
711			fprintf(stdout, "Unit started successfully");
712			if (loadeject)
713				fprintf(stdout,", Media loaded\n");
714			else
715				fprintf(stdout,"\n");
716		} else {
717			fprintf(stdout, "Unit stopped successfully");
718			if (loadeject)
719				fprintf(stdout, ", Media ejected\n");
720			else
721				fprintf(stdout, "\n");
722		}
723	else {
724		error = 1;
725		if (startstop)
726			fprintf(stdout,
727				"Error received from start unit command\n");
728		else
729			fprintf(stdout,
730				"Error received from stop unit command\n");
731
732		if (arglist & CAM_ARG_VERBOSE) {
733			cam_error_print(device, ccb, CAM_ESF_ALL,
734					CAM_EPF_ALL, stderr);
735		}
736	}
737
738	cam_freeccb(ccb);
739
740	return(error);
741}
742
743int
744scsidoinquiry(struct cam_device *device, int argc, char **argv,
745	      char *combinedopt, int retry_count, int timeout)
746{
747	int c;
748	int error = 0;
749
750	while ((c = getopt(argc, argv, combinedopt)) != -1) {
751		switch(c) {
752		case 'D':
753			arglist |= CAM_ARG_GET_STDINQ;
754			break;
755		case 'R':
756			arglist |= CAM_ARG_GET_XFERRATE;
757			break;
758		case 'S':
759			arglist |= CAM_ARG_GET_SERIAL;
760			break;
761		default:
762			break;
763		}
764	}
765
766	/*
767	 * If the user didn't specify any inquiry options, he wants all of
768	 * them.
769	 */
770	if ((arglist & CAM_ARG_INQ_MASK) == 0)
771		arglist |= CAM_ARG_INQ_MASK;
772
773	if (arglist & CAM_ARG_GET_STDINQ)
774		error = scsiinquiry(device, retry_count, timeout);
775
776	if (error != 0)
777		return(error);
778
779	if (arglist & CAM_ARG_GET_SERIAL)
780		scsiserial(device, retry_count, timeout);
781
782	if (error != 0)
783		return(error);
784
785	if (arglist & CAM_ARG_GET_XFERRATE)
786		error = camxferrate(device);
787
788	return(error);
789}
790
791static int
792scsiinquiry(struct cam_device *device, int retry_count, int timeout)
793{
794	union ccb *ccb;
795	struct scsi_inquiry_data *inq_buf;
796	int error = 0;
797
798	ccb = cam_getccb(device);
799
800	if (ccb == NULL) {
801		warnx("couldn't allocate CCB");
802		return(1);
803	}
804
805	/* cam_getccb cleans up the header, caller has to zero the payload */
806	bzero(&(&ccb->ccb_h)[1],
807	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
808
809	inq_buf = (struct scsi_inquiry_data *)malloc(
810		sizeof(struct scsi_inquiry_data));
811
812	if (inq_buf == NULL) {
813		cam_freeccb(ccb);
814		warnx("can't malloc memory for inquiry\n");
815		return(1);
816	}
817	bzero(inq_buf, sizeof(*inq_buf));
818
819	/*
820	 * Note that although the size of the inquiry buffer is the full
821	 * 256 bytes specified in the SCSI spec, we only tell the device
822	 * that we have allocated SHORT_INQUIRY_LENGTH bytes.  There are
823	 * two reasons for this:
824	 *
825	 *  - The SCSI spec says that when a length field is only 1 byte,
826	 *    a value of 0 will be interpreted as 256.  Therefore
827	 *    scsi_inquiry() will convert an inq_len (which is passed in as
828	 *    a u_int32_t, but the field in the CDB is only 1 byte) of 256
829	 *    to 0.  Evidently, very few devices meet the spec in that
830	 *    regard.  Some devices, like many Seagate disks, take the 0 as
831	 *    0, and don't return any data.  One Pioneer DVD-R drive
832	 *    returns more data than the command asked for.
833	 *
834	 *    So, since there are numerous devices that just don't work
835	 *    right with the full inquiry size, we don't send the full size.
836	 *
837	 *  - The second reason not to use the full inquiry data length is
838	 *    that we don't need it here.  The only reason we issue a
839	 *    standard inquiry is to get the vendor name, device name,
840	 *    and revision so scsi_print_inquiry() can print them.
841	 *
842	 * If, at some point in the future, more inquiry data is needed for
843	 * some reason, this code should use a procedure similar to the
844	 * probe code.  i.e., issue a short inquiry, and determine from
845	 * the additional length passed back from the device how much
846	 * inquiry data the device supports.  Once the amount the device
847	 * supports is determined, issue an inquiry for that amount and no
848	 * more.
849	 *
850	 * KDM, 2/18/2000
851	 */
852	scsi_inquiry(&ccb->csio,
853		     /* retries */ retry_count,
854		     /* cbfcnp */ NULL,
855		     /* tag_action */ MSG_SIMPLE_Q_TAG,
856		     /* inq_buf */ (u_int8_t *)inq_buf,
857		     /* inq_len */ SHORT_INQUIRY_LENGTH,
858		     /* evpd */ 0,
859		     /* page_code */ 0,
860		     /* sense_len */ SSD_FULL_SIZE,
861		     /* timeout */ timeout ? timeout : 5000);
862
863	/* Disable freezing the device queue */
864	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
865
866	if (arglist & CAM_ARG_ERR_RECOVER)
867		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
868
869	if (cam_send_ccb(device, ccb) < 0) {
870		perror("error sending SCSI inquiry");
871
872		if (arglist & CAM_ARG_VERBOSE) {
873			cam_error_print(device, ccb, CAM_ESF_ALL,
874					CAM_EPF_ALL, stderr);
875		}
876
877		cam_freeccb(ccb);
878		return(1);
879	}
880
881	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
882		error = 1;
883
884		if (arglist & CAM_ARG_VERBOSE) {
885			cam_error_print(device, ccb, CAM_ESF_ALL,
886					CAM_EPF_ALL, stderr);
887		}
888	}
889
890	cam_freeccb(ccb);
891
892	if (error != 0) {
893		free(inq_buf);
894		return(error);
895	}
896
897	fprintf(stdout, "%s%d: ", device->device_name,
898		device->dev_unit_num);
899	scsi_print_inquiry(inq_buf);
900
901	free(inq_buf);
902
903	return(0);
904}
905
906static int
907scsiserial(struct cam_device *device, int retry_count, int timeout)
908{
909	union ccb *ccb;
910	struct scsi_vpd_unit_serial_number *serial_buf;
911	char serial_num[SVPD_SERIAL_NUM_SIZE + 1];
912	int error = 0;
913
914	ccb = cam_getccb(device);
915
916	if (ccb == NULL) {
917		warnx("couldn't allocate CCB");
918		return(1);
919	}
920
921	/* cam_getccb cleans up the header, caller has to zero the payload */
922	bzero(&(&ccb->ccb_h)[1],
923	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
924
925	serial_buf = (struct scsi_vpd_unit_serial_number *)
926		malloc(sizeof(*serial_buf));
927
928	if (serial_buf == NULL) {
929		cam_freeccb(ccb);
930		warnx("can't malloc memory for serial number");
931		return(1);
932	}
933
934	scsi_inquiry(&ccb->csio,
935		     /*retries*/ retry_count,
936		     /*cbfcnp*/ NULL,
937		     /* tag_action */ MSG_SIMPLE_Q_TAG,
938		     /* inq_buf */ (u_int8_t *)serial_buf,
939		     /* inq_len */ sizeof(*serial_buf),
940		     /* evpd */ 1,
941		     /* page_code */ SVPD_UNIT_SERIAL_NUMBER,
942		     /* sense_len */ SSD_FULL_SIZE,
943		     /* timeout */ timeout ? timeout : 5000);
944
945	/* Disable freezing the device queue */
946	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
947
948	if (arglist & CAM_ARG_ERR_RECOVER)
949		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
950
951	if (cam_send_ccb(device, ccb) < 0) {
952		warn("error getting serial number");
953
954		if (arglist & CAM_ARG_VERBOSE) {
955			cam_error_print(device, ccb, CAM_ESF_ALL,
956					CAM_EPF_ALL, stderr);
957		}
958
959		cam_freeccb(ccb);
960		free(serial_buf);
961		return(1);
962	}
963
964	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
965		error = 1;
966
967		if (arglist & CAM_ARG_VERBOSE) {
968			cam_error_print(device, ccb, CAM_ESF_ALL,
969					CAM_EPF_ALL, stderr);
970		}
971	}
972
973	cam_freeccb(ccb);
974
975	if (error != 0) {
976		free(serial_buf);
977		return(error);
978	}
979
980	bcopy(serial_buf->serial_num, serial_num, serial_buf->length);
981	serial_num[serial_buf->length] = '\0';
982
983	if ((arglist & CAM_ARG_GET_STDINQ)
984	 || (arglist & CAM_ARG_GET_XFERRATE))
985		fprintf(stdout, "%s%d: Serial Number ",
986			device->device_name, device->dev_unit_num);
987
988	fprintf(stdout, "%.60s\n", serial_num);
989
990	free(serial_buf);
991
992	return(0);
993}
994
995static int
996camxferrate(struct cam_device *device)
997{
998	struct ccb_pathinq cpi;
999	u_int32_t freq = 0;
1000	u_int32_t speed = 0;
1001	union ccb *ccb;
1002	u_int mb;
1003	int retval = 0;
1004
1005	if ((retval = get_cpi(device, &cpi)) != 0)
1006		return (1);
1007
1008	ccb = cam_getccb(device);
1009
1010	if (ccb == NULL) {
1011		warnx("couldn't allocate CCB");
1012		return(1);
1013	}
1014
1015	bzero(&(&ccb->ccb_h)[1],
1016	      sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr));
1017
1018	ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1019	ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS;
1020
1021	if (((retval = cam_send_ccb(device, ccb)) < 0)
1022	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
1023		const char error_string[] = "error getting transfer settings";
1024
1025		if (retval < 0)
1026			warn(error_string);
1027		else
1028			warnx(error_string);
1029
1030		if (arglist & CAM_ARG_VERBOSE)
1031			cam_error_print(device, ccb, CAM_ESF_ALL,
1032					CAM_EPF_ALL, stderr);
1033
1034		retval = 1;
1035
1036		goto xferrate_bailout;
1037
1038	}
1039
1040	speed = cpi.base_transfer_speed;
1041	freq = 0;
1042	if (ccb->cts.transport == XPORT_SPI) {
1043		struct ccb_trans_settings_spi *spi =
1044		    &ccb->cts.xport_specific.spi;
1045
1046		if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) {
1047			freq = scsi_calc_syncsrate(spi->sync_period);
1048			speed = freq;
1049		}
1050		if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
1051			speed *= (0x01 << spi->bus_width);
1052		}
1053	} else if (ccb->cts.transport == XPORT_FC) {
1054		struct ccb_trans_settings_fc *fc =
1055		    &ccb->cts.xport_specific.fc;
1056
1057		if (fc->valid & CTS_FC_VALID_SPEED)
1058			speed = fc->bitrate;
1059	} else if (ccb->cts.transport == XPORT_SAS) {
1060		struct ccb_trans_settings_sas *sas =
1061		    &ccb->cts.xport_specific.sas;
1062
1063		if (sas->valid & CTS_SAS_VALID_SPEED)
1064			speed = sas->bitrate;
1065	} else if (ccb->cts.transport == XPORT_ATA) {
1066		struct ccb_trans_settings_pata *pata =
1067		    &ccb->cts.xport_specific.ata;
1068
1069		if (pata->valid & CTS_ATA_VALID_MODE)
1070			speed = ata_mode2speed(pata->mode);
1071	} else if (ccb->cts.transport == XPORT_SATA) {
1072		struct	ccb_trans_settings_sata *sata =
1073		    &ccb->cts.xport_specific.sata;
1074
1075		if (sata->valid & CTS_SATA_VALID_REVISION)
1076			speed = ata_revision2speed(sata->revision);
1077	}
1078
1079	mb = speed / 1000;
1080	if (mb > 0) {
1081		fprintf(stdout, "%s%d: %d.%03dMB/s transfers",
1082			device->device_name, device->dev_unit_num,
1083			mb, speed % 1000);
1084	} else {
1085		fprintf(stdout, "%s%d: %dKB/s transfers",
1086			device->device_name, device->dev_unit_num,
1087			speed);
1088	}
1089
1090	if (ccb->cts.transport == XPORT_SPI) {
1091		struct ccb_trans_settings_spi *spi =
1092		    &ccb->cts.xport_specific.spi;
1093
1094		if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
1095		 && (spi->sync_offset != 0))
1096			fprintf(stdout, " (%d.%03dMHz, offset %d", freq / 1000,
1097				freq % 1000, spi->sync_offset);
1098
1099		if (((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0)
1100		 && (spi->bus_width > 0)) {
1101			if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
1102			 && (spi->sync_offset != 0)) {
1103				fprintf(stdout, ", ");
1104			} else {
1105				fprintf(stdout, " (");
1106			}
1107			fprintf(stdout, "%dbit)", 8 * (0x01 << spi->bus_width));
1108		} else if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
1109		 && (spi->sync_offset != 0)) {
1110			fprintf(stdout, ")");
1111		}
1112	} else if (ccb->cts.transport == XPORT_ATA) {
1113		struct ccb_trans_settings_pata *pata =
1114		    &ccb->cts.xport_specific.ata;
1115
1116		printf(" (");
1117		if (pata->valid & CTS_ATA_VALID_MODE)
1118			printf("%s, ", ata_mode2string(pata->mode));
1119		if ((pata->valid & CTS_ATA_VALID_ATAPI) && pata->atapi != 0)
1120			printf("ATAPI %dbytes, ", pata->atapi);
1121		if (pata->valid & CTS_ATA_VALID_BYTECOUNT)
1122			printf("PIO %dbytes", pata->bytecount);
1123		printf(")");
1124	} else if (ccb->cts.transport == XPORT_SATA) {
1125		struct ccb_trans_settings_sata *sata =
1126		    &ccb->cts.xport_specific.sata;
1127
1128		printf(" (");
1129		if (sata->valid & CTS_SATA_VALID_REVISION)
1130			printf("SATA %d.x, ", sata->revision);
1131		else
1132			printf("SATA, ");
1133		if (sata->valid & CTS_SATA_VALID_MODE)
1134			printf("%s, ", ata_mode2string(sata->mode));
1135		if ((sata->valid & CTS_SATA_VALID_ATAPI) && sata->atapi != 0)
1136			printf("ATAPI %dbytes, ", sata->atapi);
1137		if (sata->valid & CTS_SATA_VALID_BYTECOUNT)
1138			printf("PIO %dbytes", sata->bytecount);
1139		printf(")");
1140	}
1141
1142	if (ccb->cts.protocol == PROTO_SCSI) {
1143		struct ccb_trans_settings_scsi *scsi =
1144		    &ccb->cts.proto_specific.scsi;
1145		if (scsi->valid & CTS_SCSI_VALID_TQ) {
1146			if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) {
1147				fprintf(stdout, ", Command Queueing Enabled");
1148			}
1149		}
1150	}
1151
1152        fprintf(stdout, "\n");
1153
1154xferrate_bailout:
1155
1156	cam_freeccb(ccb);
1157
1158	return(retval);
1159}
1160
1161static void
1162atahpa_print(struct ata_params *parm, u_int64_t hpasize, int header)
1163{
1164	u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
1165				((u_int32_t)parm->lba_size_2 << 16);
1166
1167	u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
1168				((u_int64_t)parm->lba_size48_2 << 16) |
1169				((u_int64_t)parm->lba_size48_3 << 32) |
1170				((u_int64_t)parm->lba_size48_4 << 48);
1171
1172	if (header) {
1173		printf("\nFeature                      "
1174		       "Support  Enabled   Value\n");
1175	}
1176
1177	printf("Host Protected Area (HPA)      ");
1178	if (parm->support.command1 & ATA_SUPPORT_PROTECTED) {
1179		u_int64_t lba = lbasize48 ? lbasize48 : lbasize;
1180		printf("yes      %s     %ju/%ju\n", (hpasize > lba) ? "yes" : "no ",
1181		        lba, hpasize);
1182
1183		printf("HPA - Security                 ");
1184		if (parm->support.command1 & ATA_SUPPORT_MAXSECURITY)
1185			printf("yes\n");
1186		else
1187			printf("no\n");
1188	} else {
1189		printf("no\n");
1190	}
1191}
1192
1193static void
1194atacapprint(struct ata_params *parm)
1195{
1196	u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
1197				((u_int32_t)parm->lba_size_2 << 16);
1198
1199	u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
1200				((u_int64_t)parm->lba_size48_2 << 16) |
1201				((u_int64_t)parm->lba_size48_3 << 32) |
1202				((u_int64_t)parm->lba_size48_4 << 48);
1203
1204	printf("\n");
1205	printf("protocol              ");
1206	printf("ATA/ATAPI-%d", ata_version(parm->version_major));
1207	if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
1208		if (parm->satacapabilities & ATA_SATA_GEN3)
1209			printf(" SATA 3.x\n");
1210		else if (parm->satacapabilities & ATA_SATA_GEN2)
1211			printf(" SATA 2.x\n");
1212		else if (parm->satacapabilities & ATA_SATA_GEN1)
1213			printf(" SATA 1.x\n");
1214		else
1215			printf(" SATA\n");
1216	}
1217	else
1218		printf("\n");
1219	printf("device model          %.40s\n", parm->model);
1220	printf("firmware revision     %.8s\n", parm->revision);
1221	printf("serial number         %.20s\n", parm->serial);
1222	if (parm->enabled.extension & ATA_SUPPORT_64BITWWN) {
1223		printf("WWN                   %04x%04x%04x%04x\n",
1224		    parm->wwn[0], parm->wwn[1], parm->wwn[2], parm->wwn[3]);
1225	}
1226	if (parm->enabled.extension & ATA_SUPPORT_MEDIASN) {
1227		printf("media serial number   %.30s\n",
1228		    parm->media_serial);
1229	}
1230
1231	printf("cylinders             %d\n", parm->cylinders);
1232	printf("heads                 %d\n", parm->heads);
1233	printf("sectors/track         %d\n", parm->sectors);
1234	printf("sector size           logical %u, physical %lu, offset %lu\n",
1235	    ata_logical_sector_size(parm),
1236	    (unsigned long)ata_physical_sector_size(parm),
1237	    (unsigned long)ata_logical_sector_offset(parm));
1238
1239	if (parm->config == ATA_PROTO_CFA ||
1240	    (parm->support.command2 & ATA_SUPPORT_CFA))
1241		printf("CFA supported\n");
1242
1243	printf("LBA%ssupported         ",
1244		parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not ");
1245	if (lbasize)
1246		printf("%d sectors\n", lbasize);
1247	else
1248		printf("\n");
1249
1250	printf("LBA48%ssupported       ",
1251		parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not ");
1252	if (lbasize48)
1253		printf("%ju sectors\n", (uintmax_t)lbasize48);
1254	else
1255		printf("\n");
1256
1257	printf("PIO supported         PIO");
1258	switch (ata_max_pmode(parm)) {
1259	case ATA_PIO4:
1260		printf("4");
1261		break;
1262	case ATA_PIO3:
1263		printf("3");
1264		break;
1265	case ATA_PIO2:
1266		printf("2");
1267		break;
1268	case ATA_PIO1:
1269		printf("1");
1270		break;
1271	default:
1272		printf("0");
1273	}
1274	if ((parm->capabilities1 & ATA_SUPPORT_IORDY) == 0)
1275		printf(" w/o IORDY");
1276	printf("\n");
1277
1278	printf("DMA%ssupported         ",
1279		parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not ");
1280	if (parm->capabilities1 & ATA_SUPPORT_DMA) {
1281		if (parm->mwdmamodes & 0xff) {
1282			printf("WDMA");
1283			if (parm->mwdmamodes & 0x04)
1284				printf("2");
1285			else if (parm->mwdmamodes & 0x02)
1286				printf("1");
1287			else if (parm->mwdmamodes & 0x01)
1288				printf("0");
1289			printf(" ");
1290		}
1291		if ((parm->atavalid & ATA_FLAG_88) &&
1292		    (parm->udmamodes & 0xff)) {
1293			printf("UDMA");
1294			if (parm->udmamodes & 0x40)
1295				printf("6");
1296			else if (parm->udmamodes & 0x20)
1297				printf("5");
1298			else if (parm->udmamodes & 0x10)
1299				printf("4");
1300			else if (parm->udmamodes & 0x08)
1301				printf("3");
1302			else if (parm->udmamodes & 0x04)
1303				printf("2");
1304			else if (parm->udmamodes & 0x02)
1305				printf("1");
1306			else if (parm->udmamodes & 0x01)
1307				printf("0");
1308			printf(" ");
1309		}
1310	}
1311	printf("\n");
1312
1313	if (parm->media_rotation_rate == 1) {
1314		printf("media RPM             non-rotating\n");
1315	} else if (parm->media_rotation_rate >= 0x0401 &&
1316	    parm->media_rotation_rate <= 0xFFFE) {
1317		printf("media RPM             %d\n",
1318			parm->media_rotation_rate);
1319	}
1320
1321	printf("\nFeature                      "
1322		"Support  Enabled   Value           Vendor\n");
1323	printf("read ahead                     %s	%s\n",
1324		parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no",
1325		parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no");
1326	printf("write cache                    %s	%s\n",
1327		parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no",
1328		parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no");
1329	printf("flush cache                    %s	%s\n",
1330		parm->support.command2 & ATA_SUPPORT_FLUSHCACHE ? "yes" : "no",
1331		parm->enabled.command2 & ATA_SUPPORT_FLUSHCACHE ? "yes" : "no");
1332	printf("overlap                        %s\n",
1333		parm->capabilities1 & ATA_SUPPORT_OVERLAP ? "yes" : "no");
1334	printf("Tagged Command Queuing (TCQ)   %s	%s",
1335		parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
1336		parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no");
1337		if (parm->support.command2 & ATA_SUPPORT_QUEUED) {
1338			printf("	%d tags\n",
1339			    ATA_QUEUE_LEN(parm->queue) + 1);
1340		} else
1341			printf("\n");
1342	printf("Native Command Queuing (NCQ)   ");
1343	if (parm->satacapabilities != 0xffff &&
1344	    (parm->satacapabilities & ATA_SUPPORT_NCQ)) {
1345		printf("yes		%d tags\n",
1346		    ATA_QUEUE_LEN(parm->queue) + 1);
1347	} else
1348		printf("no\n");
1349	printf("SMART                          %s	%s\n",
1350		parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no",
1351		parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no");
1352	printf("microcode download             %s	%s\n",
1353		parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no",
1354		parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no");
1355	printf("security                       %s	%s\n",
1356		parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no",
1357		parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no");
1358	printf("power management               %s	%s\n",
1359		parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no",
1360		parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no");
1361	printf("advanced power management      %s	%s",
1362		parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no",
1363		parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no");
1364		if (parm->support.command2 & ATA_SUPPORT_APM) {
1365			printf("	%d/0x%02X\n",
1366			    parm->apm_value, parm->apm_value);
1367		} else
1368			printf("\n");
1369	printf("automatic acoustic management  %s	%s",
1370		parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
1371		parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no");
1372		if (parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC) {
1373			printf("	%d/0x%02X	%d/0x%02X\n",
1374			    ATA_ACOUSTIC_CURRENT(parm->acoustic),
1375			    ATA_ACOUSTIC_CURRENT(parm->acoustic),
1376			    ATA_ACOUSTIC_VENDOR(parm->acoustic),
1377			    ATA_ACOUSTIC_VENDOR(parm->acoustic));
1378		} else
1379			printf("\n");
1380	printf("media status notification      %s	%s\n",
1381		parm->support.command2 & ATA_SUPPORT_NOTIFY ? "yes" : "no",
1382		parm->enabled.command2 & ATA_SUPPORT_NOTIFY ? "yes" : "no");
1383	printf("power-up in Standby            %s	%s\n",
1384		parm->support.command2 & ATA_SUPPORT_STANDBY ? "yes" : "no",
1385		parm->enabled.command2 & ATA_SUPPORT_STANDBY ? "yes" : "no");
1386	printf("write-read-verify              %s	%s",
1387		parm->support2 & ATA_SUPPORT_WRITEREADVERIFY ? "yes" : "no",
1388		parm->enabled2 & ATA_SUPPORT_WRITEREADVERIFY ? "yes" : "no");
1389		if (parm->support2 & ATA_SUPPORT_WRITEREADVERIFY) {
1390			printf("	%d/0x%x\n",
1391			    parm->wrv_mode, parm->wrv_mode);
1392		} else
1393			printf("\n");
1394	printf("unload                         %s	%s\n",
1395		parm->support.extension & ATA_SUPPORT_UNLOAD ? "yes" : "no",
1396		parm->enabled.extension & ATA_SUPPORT_UNLOAD ? "yes" : "no");
1397	printf("free-fall                      %s	%s\n",
1398		parm->support2 & ATA_SUPPORT_FREEFALL ? "yes" : "no",
1399		parm->enabled2 & ATA_SUPPORT_FREEFALL ? "yes" : "no");
1400	printf("Data Set Management (DSM/TRIM) ");
1401	if (parm->support_dsm & ATA_SUPPORT_DSM_TRIM) {
1402		printf("yes\n");
1403		printf("DSM - max 512byte blocks       ");
1404		if (parm->max_dsm_blocks == 0x00)
1405			printf("yes              not specified\n");
1406		else
1407			printf("yes              %d\n",
1408				parm->max_dsm_blocks);
1409
1410		printf("DSM - deterministic read       ");
1411		if (parm->support3 & ATA_SUPPORT_DRAT) {
1412			if (parm->support3 & ATA_SUPPORT_RZAT)
1413				printf("yes              zeroed\n");
1414			else
1415				printf("yes              any value\n");
1416		} else {
1417			printf("no\n");
1418		}
1419	} else {
1420		printf("no\n");
1421	}
1422}
1423
1424static int
1425scsi_cam_pass_16_send(struct cam_device *device, union ccb *ccb, int quiet)
1426{
1427	struct ata_pass_16 *ata_pass_16;
1428	struct ata_cmd ata_cmd;
1429
1430	ata_pass_16 = (struct ata_pass_16 *)ccb->csio.cdb_io.cdb_bytes;
1431	ata_cmd.command = ata_pass_16->command;
1432	ata_cmd.control = ata_pass_16->control;
1433	ata_cmd.features = ata_pass_16->features;
1434
1435	if (arglist & CAM_ARG_VERBOSE) {
1436		warnx("sending ATA %s via pass_16 with timeout of %u msecs",
1437		      ata_op_string(&ata_cmd),
1438		      ccb->csio.ccb_h.timeout);
1439	}
1440
1441	/* Disable freezing the device queue */
1442	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
1443
1444	if (arglist & CAM_ARG_ERR_RECOVER)
1445		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
1446
1447	if (cam_send_ccb(device, ccb) < 0) {
1448		if (quiet != 1 || arglist & CAM_ARG_VERBOSE) {
1449			warn("error sending ATA %s via pass_16",
1450			     ata_op_string(&ata_cmd));
1451		}
1452
1453		if (arglist & CAM_ARG_VERBOSE) {
1454			cam_error_print(device, ccb, CAM_ESF_ALL,
1455					CAM_EPF_ALL, stderr);
1456		}
1457
1458		return (1);
1459	}
1460
1461	if (!(ata_pass_16->flags & AP_FLAG_CHK_COND) &&
1462	    (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1463		if (quiet != 1 || arglist & CAM_ARG_VERBOSE) {
1464			warnx("ATA %s via pass_16 failed",
1465			      ata_op_string(&ata_cmd));
1466		}
1467		if (arglist & CAM_ARG_VERBOSE) {
1468			cam_error_print(device, ccb, CAM_ESF_ALL,
1469					CAM_EPF_ALL, stderr);
1470		}
1471
1472		return (1);
1473	}
1474
1475	return (0);
1476}
1477
1478
1479static int
1480ata_cam_send(struct cam_device *device, union ccb *ccb, int quiet)
1481{
1482	if (arglist & CAM_ARG_VERBOSE) {
1483		warnx("sending ATA %s with timeout of %u msecs",
1484		      ata_op_string(&(ccb->ataio.cmd)),
1485		      ccb->ataio.ccb_h.timeout);
1486	}
1487
1488	/* Disable freezing the device queue */
1489	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
1490
1491	if (arglist & CAM_ARG_ERR_RECOVER)
1492		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
1493
1494	if (cam_send_ccb(device, ccb) < 0) {
1495		if (quiet != 1 || arglist & CAM_ARG_VERBOSE) {
1496			warn("error sending ATA %s",
1497			     ata_op_string(&(ccb->ataio.cmd)));
1498		}
1499
1500		if (arglist & CAM_ARG_VERBOSE) {
1501			cam_error_print(device, ccb, CAM_ESF_ALL,
1502					CAM_EPF_ALL, stderr);
1503		}
1504
1505		return (1);
1506	}
1507
1508	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1509		if (quiet != 1 || arglist & CAM_ARG_VERBOSE) {
1510			warnx("ATA %s failed: %d",
1511			      ata_op_string(&(ccb->ataio.cmd)), quiet);
1512		}
1513
1514		if (arglist & CAM_ARG_VERBOSE) {
1515			cam_error_print(device, ccb, CAM_ESF_ALL,
1516					CAM_EPF_ALL, stderr);
1517		}
1518
1519		return (1);
1520	}
1521
1522	return (0);
1523}
1524
1525static int
1526ata_do_pass_16(struct cam_device *device, union ccb *ccb, int retries,
1527	       u_int32_t flags, u_int8_t protocol, u_int8_t ata_flags,
1528	       u_int8_t tag_action, u_int8_t command, u_int8_t features,
1529	       u_int64_t lba, u_int8_t sector_count, u_int8_t *data_ptr,
1530	       u_int16_t dxfer_len, int timeout, int quiet)
1531{
1532	if (data_ptr != NULL) {
1533		ata_flags |= AP_FLAG_BYT_BLOK_BYTES |
1534			    AP_FLAG_TLEN_SECT_CNT;
1535		if (flags & CAM_DIR_OUT)
1536			ata_flags |= AP_FLAG_TDIR_TO_DEV;
1537		else
1538			ata_flags |= AP_FLAG_TDIR_FROM_DEV;
1539	} else {
1540		ata_flags |= AP_FLAG_TLEN_NO_DATA;
1541	}
1542
1543	bzero(&(&ccb->ccb_h)[1],
1544	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
1545
1546	scsi_ata_pass_16(&ccb->csio,
1547			 retries,
1548			 NULL,
1549			 flags,
1550			 tag_action,
1551			 protocol,
1552			 ata_flags,
1553			 features,
1554			 sector_count,
1555			 lba,
1556			 command,
1557			 /*control*/0,
1558			 data_ptr,
1559			 dxfer_len,
1560			 /*sense_len*/SSD_FULL_SIZE,
1561			 timeout);
1562
1563	return scsi_cam_pass_16_send(device, ccb, quiet);
1564}
1565
1566static int
1567ata_try_pass_16(struct cam_device *device)
1568{
1569	struct ccb_pathinq cpi;
1570
1571	if (get_cpi(device, &cpi) != 0) {
1572		warnx("couldn't get CPI");
1573		return (-1);
1574	}
1575
1576	if (cpi.protocol == PROTO_SCSI) {
1577		/* possibly compatible with pass_16 */
1578		return (1);
1579	}
1580
1581	/* likely not compatible with pass_16 */
1582	return (0);
1583}
1584
1585static int
1586ata_do_28bit_cmd(struct cam_device *device, union ccb *ccb, int retries,
1587		 u_int32_t flags, u_int8_t protocol, u_int8_t tag_action,
1588		 u_int8_t command, u_int8_t features, u_int32_t lba,
1589		 u_int8_t sector_count, u_int8_t *data_ptr, u_int16_t dxfer_len,
1590		 int timeout, int quiet)
1591{
1592
1593
1594	switch (ata_try_pass_16(device)) {
1595	case -1:
1596		return (1);
1597	case 1:
1598		/* Try using SCSI Passthrough */
1599		return ata_do_pass_16(device, ccb, retries, flags, protocol,
1600				      0, tag_action, command, features, lba,
1601				      sector_count, data_ptr, dxfer_len,
1602				      timeout, quiet);
1603	}
1604
1605	bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_ataio) -
1606	      sizeof(struct ccb_hdr));
1607	cam_fill_ataio(&ccb->ataio,
1608		       retries,
1609		       NULL,
1610		       flags,
1611		       tag_action,
1612		       data_ptr,
1613		       dxfer_len,
1614		       timeout);
1615
1616	ata_28bit_cmd(&ccb->ataio, command, features, lba, sector_count);
1617	return ata_cam_send(device, ccb, quiet);
1618}
1619
1620static int
1621ata_do_cmd(struct cam_device *device, union ccb *ccb, int retries,
1622	   u_int32_t flags, u_int8_t protocol, u_int8_t ata_flags,
1623	   u_int8_t tag_action, u_int8_t command, u_int8_t features,
1624	   u_int64_t lba, u_int8_t sector_count, u_int8_t *data_ptr,
1625	   u_int16_t dxfer_len, int timeout, int force48bit)
1626{
1627	int retval;
1628
1629	retval = ata_try_pass_16(device);
1630	if (retval == -1)
1631		return (1);
1632
1633	if (retval == 1) {
1634		int error;
1635
1636		/* Try using SCSI Passthrough */
1637		error = ata_do_pass_16(device, ccb, retries, flags, protocol,
1638				      ata_flags, tag_action, command, features,
1639				      lba, sector_count, data_ptr, dxfer_len,
1640				      timeout, 0);
1641
1642		if (ata_flags & AP_FLAG_CHK_COND) {
1643			/* Decode ata_res from sense data */
1644			struct ata_res_pass16 *res_pass16;
1645			struct ata_res *res;
1646			u_int i;
1647			u_int16_t *ptr;
1648
1649			/* sense_data is 4 byte aligned */
1650			ptr = (uint16_t*)(uintptr_t)&ccb->csio.sense_data;
1651			for (i = 0; i < sizeof(*res_pass16) / 2; i++)
1652				ptr[i] = le16toh(ptr[i]);
1653
1654			/* sense_data is 4 byte aligned */
1655			res_pass16 = (struct ata_res_pass16 *)(uintptr_t)
1656			    &ccb->csio.sense_data;
1657			res = &ccb->ataio.res;
1658			res->flags = res_pass16->flags;
1659			res->status = res_pass16->status;
1660			res->error = res_pass16->error;
1661			res->lba_low = res_pass16->lba_low;
1662			res->lba_mid = res_pass16->lba_mid;
1663			res->lba_high = res_pass16->lba_high;
1664			res->device = res_pass16->device;
1665			res->lba_low_exp = res_pass16->lba_low_exp;
1666			res->lba_mid_exp = res_pass16->lba_mid_exp;
1667			res->lba_high_exp = res_pass16->lba_high_exp;
1668			res->sector_count = res_pass16->sector_count;
1669			res->sector_count_exp = res_pass16->sector_count_exp;
1670		}
1671
1672		return (error);
1673	}
1674
1675	bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_ataio) -
1676	      sizeof(struct ccb_hdr));
1677	cam_fill_ataio(&ccb->ataio,
1678		       retries,
1679		       NULL,
1680		       flags,
1681		       tag_action,
1682		       data_ptr,
1683		       dxfer_len,
1684		       timeout);
1685
1686	if (force48bit || lba > ATA_MAX_28BIT_LBA)
1687		ata_48bit_cmd(&ccb->ataio, command, features, lba, sector_count);
1688	else
1689		ata_28bit_cmd(&ccb->ataio, command, features, lba, sector_count);
1690
1691	if (ata_flags & AP_FLAG_CHK_COND)
1692		ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT;
1693
1694	return ata_cam_send(device, ccb, 0);
1695}
1696
1697static void
1698dump_data(uint16_t *ptr, uint32_t len)
1699{
1700	u_int i;
1701
1702	for (i = 0; i < len / 2; i++) {
1703		if ((i % 8) == 0)
1704			printf(" %3d: ", i);
1705		printf("%04hx ", ptr[i]);
1706		if ((i % 8) == 7)
1707			printf("\n");
1708	}
1709	if ((i % 8) != 7)
1710		printf("\n");
1711}
1712
1713static int
1714atahpa_proc_resp(struct cam_device *device, union ccb *ccb,
1715		 int is48bit, u_int64_t *hpasize)
1716{
1717	struct ata_res *res;
1718
1719	res = &ccb->ataio.res;
1720	if (res->status & ATA_STATUS_ERROR) {
1721		if (arglist & CAM_ARG_VERBOSE) {
1722			cam_error_print(device, ccb, CAM_ESF_ALL,
1723					CAM_EPF_ALL, stderr);
1724			printf("error = 0x%02x, sector_count = 0x%04x, "
1725			       "device = 0x%02x, status = 0x%02x\n",
1726			       res->error, res->sector_count,
1727			       res->device, res->status);
1728		}
1729
1730		if (res->error & ATA_ERROR_ID_NOT_FOUND) {
1731			warnx("Max address has already been set since "
1732			      "last power-on or hardware reset");
1733		}
1734
1735		return (1);
1736	}
1737
1738	if (arglist & CAM_ARG_VERBOSE) {
1739		fprintf(stdout, "%s%d: Raw native max data:\n",
1740			device->device_name, device->dev_unit_num);
1741		/* res is 4 byte aligned */
1742		dump_data((uint16_t*)(uintptr_t)res, sizeof(struct ata_res));
1743
1744		printf("error = 0x%02x, sector_count = 0x%04x, device = 0x%02x, "
1745		       "status = 0x%02x\n", res->error, res->sector_count,
1746		       res->device, res->status);
1747	}
1748
1749	if (hpasize != NULL) {
1750		if (is48bit) {
1751			*hpasize = (((u_int64_t)((res->lba_high_exp << 16) |
1752			    (res->lba_mid_exp << 8) | res->lba_low_exp) << 24) |
1753			    ((res->lba_high << 16) | (res->lba_mid << 8) |
1754			    res->lba_low)) + 1;
1755		} else {
1756			*hpasize = (((res->device & 0x0f) << 24) |
1757			    (res->lba_high << 16) | (res->lba_mid << 8) |
1758			    res->lba_low) + 1;
1759		}
1760	}
1761
1762	return (0);
1763}
1764
1765static int
1766ata_read_native_max(struct cam_device *device, int retry_count,
1767		      u_int32_t timeout, union ccb *ccb,
1768		      struct ata_params *parm, u_int64_t *hpasize)
1769{
1770	int error;
1771	u_int cmd, is48bit;
1772	u_int8_t protocol;
1773
1774	is48bit = parm->support.command2 & ATA_SUPPORT_ADDRESS48;
1775	protocol = AP_PROTO_NON_DATA;
1776
1777	if (is48bit) {
1778		cmd = ATA_READ_NATIVE_MAX_ADDRESS48;
1779		protocol |= AP_EXTEND;
1780	} else {
1781		cmd = ATA_READ_NATIVE_MAX_ADDRESS;
1782	}
1783
1784	error = ata_do_cmd(device,
1785			   ccb,
1786			   retry_count,
1787			   /*flags*/CAM_DIR_NONE,
1788			   /*protocol*/protocol,
1789			   /*ata_flags*/AP_FLAG_CHK_COND,
1790			   /*tag_action*/MSG_SIMPLE_Q_TAG,
1791			   /*command*/cmd,
1792			   /*features*/0,
1793			   /*lba*/0,
1794			   /*sector_count*/0,
1795			   /*data_ptr*/NULL,
1796			   /*dxfer_len*/0,
1797			   timeout ? timeout : 1000,
1798			   is48bit);
1799
1800	if (error)
1801		return (error);
1802
1803	return atahpa_proc_resp(device, ccb, is48bit, hpasize);
1804}
1805
1806static int
1807atahpa_set_max(struct cam_device *device, int retry_count,
1808	      u_int32_t timeout, union ccb *ccb,
1809	      int is48bit, u_int64_t maxsize, int persist)
1810{
1811	int error;
1812	u_int cmd;
1813	u_int8_t protocol;
1814
1815	protocol = AP_PROTO_NON_DATA;
1816
1817	if (is48bit) {
1818		cmd = ATA_SET_MAX_ADDRESS48;
1819		protocol |= AP_EXTEND;
1820	} else {
1821		cmd = ATA_SET_MAX_ADDRESS;
1822	}
1823
1824	/* lba's are zero indexed so the max lba is requested max - 1 */
1825	if (maxsize)
1826		maxsize--;
1827
1828	error = ata_do_cmd(device,
1829			   ccb,
1830			   retry_count,
1831			   /*flags*/CAM_DIR_NONE,
1832			   /*protocol*/protocol,
1833			   /*ata_flags*/AP_FLAG_CHK_COND,
1834			   /*tag_action*/MSG_SIMPLE_Q_TAG,
1835			   /*command*/cmd,
1836			   /*features*/ATA_HPA_FEAT_MAX_ADDR,
1837			   /*lba*/maxsize,
1838			   /*sector_count*/persist,
1839			   /*data_ptr*/NULL,
1840			   /*dxfer_len*/0,
1841			   timeout ? timeout : 1000,
1842			   is48bit);
1843
1844	if (error)
1845		return (error);
1846
1847	return atahpa_proc_resp(device, ccb, is48bit, NULL);
1848}
1849
1850static int
1851atahpa_password(struct cam_device *device, int retry_count,
1852		u_int32_t timeout, union ccb *ccb,
1853		int is48bit, struct ata_set_max_pwd *pwd)
1854{
1855	int error;
1856	u_int cmd;
1857	u_int8_t protocol;
1858
1859	protocol = AP_PROTO_PIO_OUT;
1860	cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
1861
1862	error = ata_do_cmd(device,
1863			   ccb,
1864			   retry_count,
1865			   /*flags*/CAM_DIR_OUT,
1866			   /*protocol*/protocol,
1867			   /*ata_flags*/AP_FLAG_CHK_COND,
1868			   /*tag_action*/MSG_SIMPLE_Q_TAG,
1869			   /*command*/cmd,
1870			   /*features*/ATA_HPA_FEAT_SET_PWD,
1871			   /*lba*/0,
1872			   /*sector_count*/0,
1873			   /*data_ptr*/(u_int8_t*)pwd,
1874			   /*dxfer_len*/sizeof(struct ata_set_max_pwd),
1875			   timeout ? timeout : 1000,
1876			   is48bit);
1877
1878	if (error)
1879		return (error);
1880
1881	return atahpa_proc_resp(device, ccb, is48bit, NULL);
1882}
1883
1884static int
1885atahpa_lock(struct cam_device *device, int retry_count,
1886	    u_int32_t timeout, union ccb *ccb, int is48bit)
1887{
1888	int error;
1889	u_int cmd;
1890	u_int8_t protocol;
1891
1892	protocol = AP_PROTO_NON_DATA;
1893	cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
1894
1895	error = ata_do_cmd(device,
1896			   ccb,
1897			   retry_count,
1898			   /*flags*/CAM_DIR_NONE,
1899			   /*protocol*/protocol,
1900			   /*ata_flags*/AP_FLAG_CHK_COND,
1901			   /*tag_action*/MSG_SIMPLE_Q_TAG,
1902			   /*command*/cmd,
1903			   /*features*/ATA_HPA_FEAT_LOCK,
1904			   /*lba*/0,
1905			   /*sector_count*/0,
1906			   /*data_ptr*/NULL,
1907			   /*dxfer_len*/0,
1908			   timeout ? timeout : 1000,
1909			   is48bit);
1910
1911	if (error)
1912		return (error);
1913
1914	return atahpa_proc_resp(device, ccb, is48bit, NULL);
1915}
1916
1917static int
1918atahpa_unlock(struct cam_device *device, int retry_count,
1919	      u_int32_t timeout, union ccb *ccb,
1920	      int is48bit, struct ata_set_max_pwd *pwd)
1921{
1922	int error;
1923	u_int cmd;
1924	u_int8_t protocol;
1925
1926	protocol = AP_PROTO_PIO_OUT;
1927	cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
1928
1929	error = ata_do_cmd(device,
1930			   ccb,
1931			   retry_count,
1932			   /*flags*/CAM_DIR_OUT,
1933			   /*protocol*/protocol,
1934			   /*ata_flags*/AP_FLAG_CHK_COND,
1935			   /*tag_action*/MSG_SIMPLE_Q_TAG,
1936			   /*command*/cmd,
1937			   /*features*/ATA_HPA_FEAT_UNLOCK,
1938			   /*lba*/0,
1939			   /*sector_count*/0,
1940			   /*data_ptr*/(u_int8_t*)pwd,
1941			   /*dxfer_len*/sizeof(struct ata_set_max_pwd),
1942			   timeout ? timeout : 1000,
1943			   is48bit);
1944
1945	if (error)
1946		return (error);
1947
1948	return atahpa_proc_resp(device, ccb, is48bit, NULL);
1949}
1950
1951static int
1952atahpa_freeze_lock(struct cam_device *device, int retry_count,
1953		   u_int32_t timeout, union ccb *ccb, int is48bit)
1954{
1955	int error;
1956	u_int cmd;
1957	u_int8_t protocol;
1958
1959	protocol = AP_PROTO_NON_DATA;
1960	cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
1961
1962	error = ata_do_cmd(device,
1963			   ccb,
1964			   retry_count,
1965			   /*flags*/CAM_DIR_NONE,
1966			   /*protocol*/protocol,
1967			   /*ata_flags*/AP_FLAG_CHK_COND,
1968			   /*tag_action*/MSG_SIMPLE_Q_TAG,
1969			   /*command*/cmd,
1970			   /*features*/ATA_HPA_FEAT_FREEZE,
1971			   /*lba*/0,
1972			   /*sector_count*/0,
1973			   /*data_ptr*/NULL,
1974			   /*dxfer_len*/0,
1975			   timeout ? timeout : 1000,
1976			   is48bit);
1977
1978	if (error)
1979		return (error);
1980
1981	return atahpa_proc_resp(device, ccb, is48bit, NULL);
1982}
1983
1984
1985static int
1986ata_do_identify(struct cam_device *device, int retry_count, int timeout,
1987		union ccb *ccb, struct ata_params** ident_bufp)
1988{
1989	struct ata_params *ident_buf;
1990	struct ccb_pathinq cpi;
1991	struct ccb_getdev cgd;
1992	u_int i, error;
1993	int16_t *ptr;
1994	u_int8_t command, retry_command;
1995
1996	if (get_cpi(device, &cpi) != 0) {
1997		warnx("couldn't get CPI");
1998		return (-1);
1999	}
2000
2001	/* Neither PROTO_ATAPI or PROTO_SATAPM are used in cpi.protocol */
2002	if (cpi.protocol == PROTO_ATA) {
2003		if (get_cgd(device, &cgd) != 0) {
2004			warnx("couldn't get CGD");
2005			return (-1);
2006		}
2007
2008		command = (cgd.protocol == PROTO_ATA) ?
2009		    ATA_ATA_IDENTIFY : ATA_ATAPI_IDENTIFY;
2010		retry_command = 0;
2011	} else {
2012		/* We don't know which for sure so try both */
2013		command = ATA_ATA_IDENTIFY;
2014		retry_command = ATA_ATAPI_IDENTIFY;
2015	}
2016
2017	ptr = (uint16_t *)calloc(1, sizeof(struct ata_params));
2018	if (ptr == NULL) {
2019		warnx("can't calloc memory for identify\n");
2020		return (1);
2021	}
2022
2023	error = ata_do_28bit_cmd(device,
2024				 ccb,
2025				 /*retries*/retry_count,
2026				 /*flags*/CAM_DIR_IN,
2027				 /*protocol*/AP_PROTO_PIO_IN,
2028				 /*tag_action*/MSG_SIMPLE_Q_TAG,
2029				 /*command*/command,
2030				 /*features*/0,
2031				 /*lba*/0,
2032				 /*sector_count*/(u_int8_t)sizeof(struct ata_params),
2033				 /*data_ptr*/(u_int8_t *)ptr,
2034				 /*dxfer_len*/sizeof(struct ata_params),
2035				 /*timeout*/timeout ? timeout : 30 * 1000,
2036				 /*quiet*/1);
2037
2038	if (error != 0) {
2039		if (retry_command == 0) {
2040			free(ptr);
2041			return (1);
2042		}
2043		error = ata_do_28bit_cmd(device,
2044					 ccb,
2045					 /*retries*/retry_count,
2046					 /*flags*/CAM_DIR_IN,
2047					 /*protocol*/AP_PROTO_PIO_IN,
2048					 /*tag_action*/MSG_SIMPLE_Q_TAG,
2049					 /*command*/retry_command,
2050					 /*features*/0,
2051					 /*lba*/0,
2052					 /*sector_count*/(u_int8_t)
2053					     sizeof(struct ata_params),
2054					 /*data_ptr*/(u_int8_t *)ptr,
2055					 /*dxfer_len*/sizeof(struct ata_params),
2056					 /*timeout*/timeout ? timeout : 30 * 1000,
2057					 /*quiet*/0);
2058
2059		if (error != 0) {
2060			free(ptr);
2061			return (1);
2062		}
2063	}
2064
2065	error = 1;
2066	for (i = 0; i < sizeof(struct ata_params) / 2; i++) {
2067		ptr[i] = le16toh(ptr[i]);
2068		if (ptr[i] != 0)
2069			error = 0;
2070	}
2071
2072	if (arglist & CAM_ARG_VERBOSE) {
2073		fprintf(stdout, "%s%d: Raw identify data:\n",
2074		    device->device_name, device->dev_unit_num);
2075		dump_data(ptr, sizeof(struct ata_params));
2076	}
2077
2078	/* check for invalid (all zero) response */
2079	if (error != 0) {
2080		warnx("Invalid identify response detected");
2081		free(ptr);
2082		return (error);
2083	}
2084
2085	ident_buf = (struct ata_params *)ptr;
2086	if (strncmp(ident_buf->model, "FX", 2) &&
2087	    strncmp(ident_buf->model, "NEC", 3) &&
2088	    strncmp(ident_buf->model, "Pioneer", 7) &&
2089	    strncmp(ident_buf->model, "SHARP", 5)) {
2090		ata_bswap(ident_buf->model, sizeof(ident_buf->model));
2091		ata_bswap(ident_buf->revision, sizeof(ident_buf->revision));
2092		ata_bswap(ident_buf->serial, sizeof(ident_buf->serial));
2093		ata_bswap(ident_buf->media_serial, sizeof(ident_buf->media_serial));
2094	}
2095	ata_btrim(ident_buf->model, sizeof(ident_buf->model));
2096	ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model));
2097	ata_btrim(ident_buf->revision, sizeof(ident_buf->revision));
2098	ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision));
2099	ata_btrim(ident_buf->serial, sizeof(ident_buf->serial));
2100	ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial));
2101	ata_btrim(ident_buf->media_serial, sizeof(ident_buf->media_serial));
2102	ata_bpack(ident_buf->media_serial, ident_buf->media_serial,
2103	    sizeof(ident_buf->media_serial));
2104
2105	*ident_bufp = ident_buf;
2106
2107	return (0);
2108}
2109
2110
2111static int
2112ataidentify(struct cam_device *device, int retry_count, int timeout)
2113{
2114	union ccb *ccb;
2115	struct ata_params *ident_buf;
2116	u_int64_t hpasize;
2117
2118	if ((ccb = cam_getccb(device)) == NULL) {
2119		warnx("couldn't allocate CCB");
2120		return (1);
2121	}
2122
2123	if (ata_do_identify(device, retry_count, timeout, ccb, &ident_buf) != 0) {
2124		cam_freeccb(ccb);
2125		return (1);
2126	}
2127
2128	if (ident_buf->support.command1 & ATA_SUPPORT_PROTECTED) {
2129		if (ata_read_native_max(device, retry_count, timeout, ccb,
2130					ident_buf, &hpasize) != 0) {
2131			cam_freeccb(ccb);
2132			return (1);
2133		}
2134	} else {
2135		hpasize = 0;
2136	}
2137
2138	printf("%s%d: ", device->device_name, device->dev_unit_num);
2139	ata_print_ident(ident_buf);
2140	camxferrate(device);
2141	atacapprint(ident_buf);
2142	atahpa_print(ident_buf, hpasize, 0);
2143
2144	free(ident_buf);
2145	cam_freeccb(ccb);
2146
2147	return (0);
2148}
2149#endif /* MINIMALISTIC */
2150
2151
2152#ifndef MINIMALISTIC
2153enum {
2154	ATA_SECURITY_ACTION_PRINT,
2155	ATA_SECURITY_ACTION_FREEZE,
2156	ATA_SECURITY_ACTION_UNLOCK,
2157	ATA_SECURITY_ACTION_DISABLE,
2158	ATA_SECURITY_ACTION_ERASE,
2159	ATA_SECURITY_ACTION_ERASE_ENHANCED,
2160	ATA_SECURITY_ACTION_SET_PASSWORD
2161};
2162
2163static void
2164atasecurity_print_time(u_int16_t tw)
2165{
2166
2167	if (tw == 0)
2168		printf("unspecified");
2169	else if (tw >= 255)
2170		printf("> 508 min");
2171	else
2172		printf("%i min", 2 * tw);
2173}
2174
2175static u_int32_t
2176atasecurity_erase_timeout_msecs(u_int16_t timeout)
2177{
2178
2179	if (timeout == 0)
2180		return 2 * 3600 * 1000; /* default: two hours */
2181	else if (timeout > 255)
2182		return (508 + 60) * 60 * 1000; /* spec says > 508 minutes */
2183
2184	return ((2 * timeout) + 5) * 60 * 1000; /* add a 5min margin */
2185}
2186
2187
2188static void
2189atasecurity_notify(u_int8_t command, struct ata_security_password *pwd)
2190{
2191	struct ata_cmd cmd;
2192
2193	bzero(&cmd, sizeof(cmd));
2194	cmd.command = command;
2195	printf("Issuing %s", ata_op_string(&cmd));
2196
2197	if (pwd != NULL) {
2198		char pass[sizeof(pwd->password)+1];
2199
2200		/* pwd->password may not be null terminated */
2201		pass[sizeof(pwd->password)] = '\0';
2202		strncpy(pass, pwd->password, sizeof(pwd->password));
2203		printf(" password='%s', user='%s'",
2204			pass,
2205			(pwd->ctrl & ATA_SECURITY_PASSWORD_MASTER) ?
2206			"master" : "user");
2207
2208		if (command == ATA_SECURITY_SET_PASSWORD) {
2209			printf(", mode='%s'",
2210			       (pwd->ctrl & ATA_SECURITY_LEVEL_MAXIMUM) ?
2211			       "maximum" : "high");
2212		}
2213	}
2214
2215	printf("\n");
2216}
2217
2218static int
2219atasecurity_freeze(struct cam_device *device, union ccb *ccb,
2220		   int retry_count, u_int32_t timeout, int quiet)
2221{
2222
2223	if (quiet == 0)
2224		atasecurity_notify(ATA_SECURITY_FREEZE_LOCK, NULL);
2225
2226	return ata_do_28bit_cmd(device,
2227				ccb,
2228				retry_count,
2229				/*flags*/CAM_DIR_NONE,
2230				/*protocol*/AP_PROTO_NON_DATA,
2231				/*tag_action*/MSG_SIMPLE_Q_TAG,
2232				/*command*/ATA_SECURITY_FREEZE_LOCK,
2233				/*features*/0,
2234				/*lba*/0,
2235				/*sector_count*/0,
2236				/*data_ptr*/NULL,
2237				/*dxfer_len*/0,
2238				/*timeout*/timeout,
2239				/*quiet*/0);
2240}
2241
2242static int
2243atasecurity_unlock(struct cam_device *device, union ccb *ccb,
2244		   int retry_count, u_int32_t timeout,
2245		   struct ata_security_password *pwd, int quiet)
2246{
2247
2248	if (quiet == 0)
2249		atasecurity_notify(ATA_SECURITY_UNLOCK, pwd);
2250
2251	return ata_do_28bit_cmd(device,
2252				ccb,
2253				retry_count,
2254				/*flags*/CAM_DIR_OUT,
2255				/*protocol*/AP_PROTO_PIO_OUT,
2256				/*tag_action*/MSG_SIMPLE_Q_TAG,
2257				/*command*/ATA_SECURITY_UNLOCK,
2258				/*features*/0,
2259				/*lba*/0,
2260				/*sector_count*/0,
2261				/*data_ptr*/(u_int8_t *)pwd,
2262				/*dxfer_len*/sizeof(*pwd),
2263				/*timeout*/timeout,
2264				/*quiet*/0);
2265}
2266
2267static int
2268atasecurity_disable(struct cam_device *device, union ccb *ccb,
2269		    int retry_count, u_int32_t timeout,
2270		    struct ata_security_password *pwd, int quiet)
2271{
2272
2273	if (quiet == 0)
2274		atasecurity_notify(ATA_SECURITY_DISABLE_PASSWORD, pwd);
2275	return ata_do_28bit_cmd(device,
2276				ccb,
2277				retry_count,
2278				/*flags*/CAM_DIR_OUT,
2279				/*protocol*/AP_PROTO_PIO_OUT,
2280				/*tag_action*/MSG_SIMPLE_Q_TAG,
2281				/*command*/ATA_SECURITY_DISABLE_PASSWORD,
2282				/*features*/0,
2283				/*lba*/0,
2284				/*sector_count*/0,
2285				/*data_ptr*/(u_int8_t *)pwd,
2286				/*dxfer_len*/sizeof(*pwd),
2287				/*timeout*/timeout,
2288				/*quiet*/0);
2289}
2290
2291
2292static int
2293atasecurity_erase_confirm(struct cam_device *device,
2294			  struct ata_params* ident_buf)
2295{
2296
2297	printf("\nYou are about to ERASE ALL DATA from the following"
2298	       " device:\n%s%d,%s%d: ", device->device_name,
2299	       device->dev_unit_num, device->given_dev_name,
2300	       device->given_unit_number);
2301	ata_print_ident(ident_buf);
2302
2303	for(;;) {
2304		char str[50];
2305		printf("\nAre you SURE you want to ERASE ALL DATA? (yes/no) ");
2306
2307		if (fgets(str, sizeof(str), stdin) != NULL) {
2308			if (strncasecmp(str, "yes", 3) == 0) {
2309				return (1);
2310			} else if (strncasecmp(str, "no", 2) == 0) {
2311				return (0);
2312			} else {
2313				printf("Please answer \"yes\" or "
2314				       "\"no\"\n");
2315			}
2316		}
2317	}
2318
2319	/* NOTREACHED */
2320	return (0);
2321}
2322
2323static int
2324atasecurity_erase(struct cam_device *device, union ccb *ccb,
2325		  int retry_count, u_int32_t timeout,
2326		  u_int32_t erase_timeout,
2327		  struct ata_security_password *pwd, int quiet)
2328{
2329	int error;
2330
2331	if (quiet == 0)
2332		atasecurity_notify(ATA_SECURITY_ERASE_PREPARE, NULL);
2333
2334	error = ata_do_28bit_cmd(device,
2335				 ccb,
2336				 retry_count,
2337				 /*flags*/CAM_DIR_NONE,
2338				 /*protocol*/AP_PROTO_NON_DATA,
2339				 /*tag_action*/MSG_SIMPLE_Q_TAG,
2340				 /*command*/ATA_SECURITY_ERASE_PREPARE,
2341				 /*features*/0,
2342				 /*lba*/0,
2343				 /*sector_count*/0,
2344				 /*data_ptr*/NULL,
2345				 /*dxfer_len*/0,
2346				 /*timeout*/timeout,
2347				 /*quiet*/0);
2348
2349	if (error != 0)
2350		return error;
2351
2352	if (quiet == 0)
2353		atasecurity_notify(ATA_SECURITY_ERASE_UNIT, pwd);
2354
2355	error = ata_do_28bit_cmd(device,
2356				 ccb,
2357				 retry_count,
2358				 /*flags*/CAM_DIR_OUT,
2359				 /*protocol*/AP_PROTO_PIO_OUT,
2360				 /*tag_action*/MSG_SIMPLE_Q_TAG,
2361				 /*command*/ATA_SECURITY_ERASE_UNIT,
2362				 /*features*/0,
2363				 /*lba*/0,
2364				 /*sector_count*/0,
2365				 /*data_ptr*/(u_int8_t *)pwd,
2366				 /*dxfer_len*/sizeof(*pwd),
2367				 /*timeout*/erase_timeout,
2368				 /*quiet*/0);
2369
2370	if (error == 0 && quiet == 0)
2371		printf("\nErase Complete\n");
2372
2373	return error;
2374}
2375
2376static int
2377atasecurity_set_password(struct cam_device *device, union ccb *ccb,
2378			 int retry_count, u_int32_t timeout,
2379			 struct ata_security_password *pwd, int quiet)
2380{
2381
2382	if (quiet == 0)
2383		atasecurity_notify(ATA_SECURITY_SET_PASSWORD, pwd);
2384
2385	return ata_do_28bit_cmd(device,
2386				 ccb,
2387				 retry_count,
2388				 /*flags*/CAM_DIR_OUT,
2389				 /*protocol*/AP_PROTO_PIO_OUT,
2390				 /*tag_action*/MSG_SIMPLE_Q_TAG,
2391				 /*command*/ATA_SECURITY_SET_PASSWORD,
2392				 /*features*/0,
2393				 /*lba*/0,
2394				 /*sector_count*/0,
2395				 /*data_ptr*/(u_int8_t *)pwd,
2396				 /*dxfer_len*/sizeof(*pwd),
2397				 /*timeout*/timeout,
2398				 /*quiet*/0);
2399}
2400
2401static void
2402atasecurity_print(struct ata_params *parm)
2403{
2404
2405	printf("\nSecurity Option           Value\n");
2406	if (arglist & CAM_ARG_VERBOSE) {
2407		printf("status                    %04x\n",
2408		       parm->security_status);
2409	}
2410	printf("supported                 %s\n",
2411		parm->security_status & ATA_SECURITY_SUPPORTED ? "yes" : "no");
2412	if (!(parm->security_status & ATA_SECURITY_SUPPORTED))
2413		return;
2414	printf("enabled                   %s\n",
2415		parm->security_status & ATA_SECURITY_ENABLED ? "yes" : "no");
2416	printf("drive locked              %s\n",
2417		parm->security_status & ATA_SECURITY_LOCKED ? "yes" : "no");
2418	printf("security config frozen    %s\n",
2419		parm->security_status & ATA_SECURITY_FROZEN ? "yes" : "no");
2420	printf("count expired             %s\n",
2421		parm->security_status & ATA_SECURITY_COUNT_EXP ? "yes" : "no");
2422	printf("security level            %s\n",
2423		parm->security_status & ATA_SECURITY_LEVEL ? "maximum" : "high");
2424	printf("enhanced erase supported  %s\n",
2425		parm->security_status & ATA_SECURITY_ENH_SUPP ? "yes" : "no");
2426	printf("erase time                ");
2427	atasecurity_print_time(parm->erase_time);
2428	printf("\n");
2429	printf("enhanced erase time       ");
2430	atasecurity_print_time(parm->enhanced_erase_time);
2431	printf("\n");
2432	printf("master password rev       %04x%s\n",
2433		parm->master_passwd_revision,
2434		parm->master_passwd_revision == 0x0000 ||
2435		parm->master_passwd_revision == 0xFFFF ?  " (unsupported)" : "");
2436}
2437
2438/*
2439 * Validates and copies the password in optarg to the passed buffer.
2440 * If the password in optarg is the same length as the buffer then
2441 * the data will still be copied but no null termination will occur.
2442 */
2443static int
2444ata_getpwd(u_int8_t *passwd, int max, char opt)
2445{
2446	int len;
2447
2448	len = strlen(optarg);
2449	if (len > max) {
2450		warnx("-%c password is too long", opt);
2451		return (1);
2452	} else if (len == 0) {
2453		warnx("-%c password is missing", opt);
2454		return (1);
2455	} else if (optarg[0] == '-'){
2456		warnx("-%c password starts with '-' (generic arg?)", opt);
2457		return (1);
2458	} else if (strlen(passwd) != 0 && strcmp(passwd, optarg) != 0) {
2459		warnx("-%c password conflicts with existing password from -%c",
2460		      opt, pwd_opt);
2461		return (1);
2462	}
2463
2464	/* Callers pass in a buffer which does NOT need to be terminated */
2465	strncpy(passwd, optarg, max);
2466	pwd_opt = opt;
2467
2468	return (0);
2469}
2470
2471enum {
2472	ATA_HPA_ACTION_PRINT,
2473	ATA_HPA_ACTION_SET_MAX,
2474	ATA_HPA_ACTION_SET_PWD,
2475	ATA_HPA_ACTION_LOCK,
2476	ATA_HPA_ACTION_UNLOCK,
2477	ATA_HPA_ACTION_FREEZE_LOCK
2478};
2479
2480static int
2481atahpa_set_confirm(struct cam_device *device, struct ata_params* ident_buf,
2482		   u_int64_t maxsize, int persist)
2483{
2484	printf("\nYou are about to configure HPA to limit the user accessible\n"
2485	       "sectors to %ju %s on the device:\n%s%d,%s%d: ", maxsize,
2486	       persist ? "persistently" : "temporarily",
2487	       device->device_name, device->dev_unit_num,
2488	       device->given_dev_name, device->given_unit_number);
2489	ata_print_ident(ident_buf);
2490
2491	for(;;) {
2492		char str[50];
2493		printf("\nAre you SURE you want to configure HPA? (yes/no) ");
2494
2495		if (NULL != fgets(str, sizeof(str), stdin)) {
2496			if (0 == strncasecmp(str, "yes", 3)) {
2497				return (1);
2498			} else if (0 == strncasecmp(str, "no", 2)) {
2499				return (0);
2500			} else {
2501				printf("Please answer \"yes\" or "
2502				       "\"no\"\n");
2503			}
2504		}
2505	}
2506
2507	/* NOTREACHED */
2508	return (0);
2509}
2510
2511static int
2512atahpa(struct cam_device *device, int retry_count, int timeout,
2513       int argc, char **argv, char *combinedopt)
2514{
2515	union ccb *ccb;
2516	struct ata_params *ident_buf;
2517	struct ccb_getdev cgd;
2518	struct ata_set_max_pwd pwd;
2519	int error, confirm, quiet, c, action, actions, setpwd, persist;
2520	int security, is48bit, pwdsize;
2521	u_int64_t hpasize, maxsize;
2522
2523	actions = 0;
2524	setpwd = 0;
2525	confirm = 0;
2526	quiet = 0;
2527	maxsize = 0;
2528	persist = 0;
2529	security = 0;
2530
2531	memset(&pwd, 0, sizeof(pwd));
2532
2533	/* default action is to print hpa information */
2534	action = ATA_HPA_ACTION_PRINT;
2535	pwdsize = sizeof(pwd.password);
2536
2537	while ((c = getopt(argc, argv, combinedopt)) != -1) {
2538		switch(c){
2539		case 's':
2540			action = ATA_HPA_ACTION_SET_MAX;
2541			maxsize = strtoumax(optarg, NULL, 0);
2542			actions++;
2543			break;
2544
2545		case 'p':
2546			if (ata_getpwd(pwd.password, pwdsize, c) != 0)
2547				return (1);
2548			action = ATA_HPA_ACTION_SET_PWD;
2549			security = 1;
2550			actions++;
2551			break;
2552
2553		case 'l':
2554			action = ATA_HPA_ACTION_LOCK;
2555			security = 1;
2556			actions++;
2557			break;
2558
2559		case 'U':
2560			if (ata_getpwd(pwd.password, pwdsize, c) != 0)
2561				return (1);
2562			action = ATA_HPA_ACTION_UNLOCK;
2563			security = 1;
2564			actions++;
2565			break;
2566
2567		case 'f':
2568			action = ATA_HPA_ACTION_FREEZE_LOCK;
2569			security = 1;
2570			actions++;
2571			break;
2572
2573		case 'P':
2574			persist = 1;
2575			break;
2576
2577		case 'y':
2578			confirm++;
2579			break;
2580
2581		case 'q':
2582			quiet++;
2583			break;
2584		}
2585	}
2586
2587	if (actions > 1) {
2588		warnx("too many hpa actions specified");
2589		return (1);
2590	}
2591
2592	if (get_cgd(device, &cgd) != 0) {
2593		warnx("couldn't get CGD");
2594		return (1);
2595	}
2596
2597	ccb = cam_getccb(device);
2598	if (ccb == NULL) {
2599		warnx("couldn't allocate CCB");
2600		return (1);
2601	}
2602
2603	error = ata_do_identify(device, retry_count, timeout, ccb, &ident_buf);
2604	if (error != 0) {
2605		cam_freeccb(ccb);
2606		return (1);
2607	}
2608
2609	if (quiet == 0) {
2610		printf("%s%d: ", device->device_name, device->dev_unit_num);
2611		ata_print_ident(ident_buf);
2612		camxferrate(device);
2613	}
2614
2615	if (action == ATA_HPA_ACTION_PRINT) {
2616		error = ata_read_native_max(device, retry_count, timeout, ccb,
2617					    ident_buf, &hpasize);
2618		if (error == 0)
2619			atahpa_print(ident_buf, hpasize, 1);
2620
2621		cam_freeccb(ccb);
2622		free(ident_buf);
2623		return (error);
2624	}
2625
2626	if (!(ident_buf->support.command1 & ATA_SUPPORT_PROTECTED)) {
2627		warnx("HPA is not supported by this device");
2628		cam_freeccb(ccb);
2629		free(ident_buf);
2630		return (1);
2631	}
2632
2633	if (security && !(ident_buf->support.command1 & ATA_SUPPORT_MAXSECURITY)) {
2634		warnx("HPA Security is not supported by this device");
2635		cam_freeccb(ccb);
2636		free(ident_buf);
2637		return (1);
2638	}
2639
2640	is48bit = ident_buf->support.command2 & ATA_SUPPORT_ADDRESS48;
2641
2642	/*
2643	 * The ATA spec requires:
2644	 * 1. Read native max addr is called directly before set max addr
2645	 * 2. Read native max addr is NOT called before any other set max call
2646	 */
2647	switch(action) {
2648	case ATA_HPA_ACTION_SET_MAX:
2649		if (confirm == 0 &&
2650		    atahpa_set_confirm(device, ident_buf, maxsize,
2651		    persist) == 0) {
2652			cam_freeccb(ccb);
2653			free(ident_buf);
2654			return (1);
2655		}
2656
2657		error = ata_read_native_max(device, retry_count, timeout,
2658					    ccb, ident_buf, &hpasize);
2659		if (error == 0) {
2660			error = atahpa_set_max(device, retry_count, timeout,
2661					       ccb, is48bit, maxsize, persist);
2662			if (error == 0) {
2663				/* redo identify to get new lba values */
2664				error = ata_do_identify(device, retry_count,
2665							timeout, ccb,
2666							&ident_buf);
2667				atahpa_print(ident_buf, hpasize, 1);
2668			}
2669		}
2670		break;
2671
2672	case ATA_HPA_ACTION_SET_PWD:
2673		error = atahpa_password(device, retry_count, timeout,
2674					ccb, is48bit, &pwd);
2675		if (error == 0)
2676			printf("HPA password has been set\n");
2677		break;
2678
2679	case ATA_HPA_ACTION_LOCK:
2680		error = atahpa_lock(device, retry_count, timeout,
2681				    ccb, is48bit);
2682		if (error == 0)
2683			printf("HPA has been locked\n");
2684		break;
2685
2686	case ATA_HPA_ACTION_UNLOCK:
2687		error = atahpa_unlock(device, retry_count, timeout,
2688				      ccb, is48bit, &pwd);
2689		if (error == 0)
2690			printf("HPA has been unlocked\n");
2691		break;
2692
2693	case ATA_HPA_ACTION_FREEZE_LOCK:
2694		error = atahpa_freeze_lock(device, retry_count, timeout,
2695					   ccb, is48bit);
2696		if (error == 0)
2697			printf("HPA has been frozen\n");
2698		break;
2699
2700	default:
2701		errx(1, "Option currently not supported");
2702	}
2703
2704	cam_freeccb(ccb);
2705	free(ident_buf);
2706
2707	return (error);
2708}
2709
2710static int
2711atasecurity(struct cam_device *device, int retry_count, int timeout,
2712	    int argc, char **argv, char *combinedopt)
2713{
2714	union ccb *ccb;
2715	struct ata_params *ident_buf;
2716	int error, confirm, quiet, c, action, actions, setpwd;
2717	int security_enabled, erase_timeout, pwdsize;
2718	struct ata_security_password pwd;
2719
2720	actions = 0;
2721	setpwd = 0;
2722	erase_timeout = 0;
2723	confirm = 0;
2724	quiet = 0;
2725
2726	memset(&pwd, 0, sizeof(pwd));
2727
2728	/* default action is to print security information */
2729	action = ATA_SECURITY_ACTION_PRINT;
2730
2731	/* user is master by default as its safer that way */
2732	pwd.ctrl |= ATA_SECURITY_PASSWORD_MASTER;
2733	pwdsize = sizeof(pwd.password);
2734
2735	while ((c = getopt(argc, argv, combinedopt)) != -1) {
2736		switch(c){
2737		case 'f':
2738			action = ATA_SECURITY_ACTION_FREEZE;
2739			actions++;
2740			break;
2741
2742		case 'U':
2743			if (strcasecmp(optarg, "user") == 0) {
2744				pwd.ctrl |= ATA_SECURITY_PASSWORD_USER;
2745				pwd.ctrl &= ~ATA_SECURITY_PASSWORD_MASTER;
2746			} else if (strcasecmp(optarg, "master") != 0) {
2747				pwd.ctrl |= ATA_SECURITY_PASSWORD_MASTER;
2748				pwd.ctrl &= ~ATA_SECURITY_PASSWORD_USER;
2749			} else {
2750				warnx("-U argument '%s' is invalid (must be "
2751				      "'user' or 'master')", optarg);
2752				return (1);
2753			}
2754			break;
2755
2756		case 'l':
2757			if (strcasecmp(optarg, "high") == 0) {
2758				pwd.ctrl |= ATA_SECURITY_LEVEL_HIGH;
2759				pwd.ctrl &= ~ATA_SECURITY_LEVEL_MAXIMUM;
2760			} else if (strcasecmp(optarg, "maximum") == 0) {
2761				pwd.ctrl |= ATA_SECURITY_LEVEL_MAXIMUM;
2762				pwd.ctrl &= ~ATA_SECURITY_LEVEL_HIGH;
2763			} else {
2764				warnx("-l argument '%s' is unknown (must be "
2765				      "'high' or 'maximum')", optarg);
2766				return (1);
2767			}
2768			break;
2769
2770		case 'k':
2771			if (ata_getpwd(pwd.password, pwdsize, c) != 0)
2772				return (1);
2773			action = ATA_SECURITY_ACTION_UNLOCK;
2774			actions++;
2775			break;
2776
2777		case 'd':
2778			if (ata_getpwd(pwd.password, pwdsize, c) != 0)
2779				return (1);
2780			action = ATA_SECURITY_ACTION_DISABLE;
2781			actions++;
2782			break;
2783
2784		case 'e':
2785			if (ata_getpwd(pwd.password, pwdsize, c) != 0)
2786				return (1);
2787			action = ATA_SECURITY_ACTION_ERASE;
2788			actions++;
2789			break;
2790
2791		case 'h':
2792			if (ata_getpwd(pwd.password, pwdsize, c) != 0)
2793				return (1);
2794			pwd.ctrl |= ATA_SECURITY_ERASE_ENHANCED;
2795			action = ATA_SECURITY_ACTION_ERASE_ENHANCED;
2796			actions++;
2797			break;
2798
2799		case 's':
2800			if (ata_getpwd(pwd.password, pwdsize, c) != 0)
2801				return (1);
2802			setpwd = 1;
2803			if (action == ATA_SECURITY_ACTION_PRINT)
2804				action = ATA_SECURITY_ACTION_SET_PASSWORD;
2805			/*
2806			 * Don't increment action as this can be combined
2807			 * with other actions.
2808			 */
2809			break;
2810
2811		case 'y':
2812			confirm++;
2813			break;
2814
2815		case 'q':
2816			quiet++;
2817			break;
2818
2819		case 'T':
2820			erase_timeout = atoi(optarg) * 1000;
2821			break;
2822		}
2823	}
2824
2825	if (actions > 1) {
2826		warnx("too many security actions specified");
2827		return (1);
2828	}
2829
2830	if ((ccb = cam_getccb(device)) == NULL) {
2831		warnx("couldn't allocate CCB");
2832		return (1);
2833	}
2834
2835	error = ata_do_identify(device, retry_count, timeout, ccb, &ident_buf);
2836	if (error != 0) {
2837		cam_freeccb(ccb);
2838		return (1);
2839	}
2840
2841	if (quiet == 0) {
2842		printf("%s%d: ", device->device_name, device->dev_unit_num);
2843		ata_print_ident(ident_buf);
2844		camxferrate(device);
2845	}
2846
2847	if (action == ATA_SECURITY_ACTION_PRINT) {
2848		atasecurity_print(ident_buf);
2849		free(ident_buf);
2850		cam_freeccb(ccb);
2851		return (0);
2852	}
2853
2854	if ((ident_buf->support.command1 & ATA_SUPPORT_SECURITY) == 0) {
2855		warnx("Security not supported");
2856		free(ident_buf);
2857		cam_freeccb(ccb);
2858		return (1);
2859	}
2860
2861	/* default timeout 15 seconds the same as linux hdparm */
2862	timeout = timeout ? timeout : 15 * 1000;
2863
2864	security_enabled = ident_buf->security_status & ATA_SECURITY_ENABLED;
2865
2866	/* first set the password if requested */
2867	if (setpwd == 1) {
2868		/* confirm we can erase before setting the password if erasing */
2869		if (confirm == 0 &&
2870		    (action == ATA_SECURITY_ACTION_ERASE_ENHANCED ||
2871		    action == ATA_SECURITY_ACTION_ERASE) &&
2872		    atasecurity_erase_confirm(device, ident_buf) == 0) {
2873			cam_freeccb(ccb);
2874			free(ident_buf);
2875			return (error);
2876		}
2877
2878		if (pwd.ctrl & ATA_SECURITY_PASSWORD_MASTER) {
2879			pwd.revision = ident_buf->master_passwd_revision;
2880			if (pwd.revision != 0 && pwd.revision != 0xfff &&
2881			    --pwd.revision == 0) {
2882				pwd.revision = 0xfffe;
2883			}
2884		}
2885		error = atasecurity_set_password(device, ccb, retry_count,
2886						 timeout, &pwd, quiet);
2887		if (error != 0) {
2888			cam_freeccb(ccb);
2889			free(ident_buf);
2890			return (error);
2891		}
2892		security_enabled = 1;
2893	}
2894
2895	switch(action) {
2896	case ATA_SECURITY_ACTION_FREEZE:
2897		error = atasecurity_freeze(device, ccb, retry_count,
2898					   timeout, quiet);
2899		break;
2900
2901	case ATA_SECURITY_ACTION_UNLOCK:
2902		if (security_enabled) {
2903			if (ident_buf->security_status & ATA_SECURITY_LOCKED) {
2904				error = atasecurity_unlock(device, ccb,
2905					retry_count, timeout, &pwd, quiet);
2906			} else {
2907				warnx("Can't unlock, drive is not locked");
2908				error = 1;
2909			}
2910		} else {
2911			warnx("Can't unlock, security is disabled");
2912			error = 1;
2913		}
2914		break;
2915
2916	case ATA_SECURITY_ACTION_DISABLE:
2917		if (security_enabled) {
2918			/* First unlock the drive if its locked */
2919			if (ident_buf->security_status & ATA_SECURITY_LOCKED) {
2920				error = atasecurity_unlock(device, ccb,
2921							   retry_count,
2922							   timeout,
2923							   &pwd,
2924							   quiet);
2925			}
2926
2927			if (error == 0) {
2928				error = atasecurity_disable(device,
2929							    ccb,
2930							    retry_count,
2931							    timeout,
2932							    &pwd,
2933							    quiet);
2934			}
2935		} else {
2936			warnx("Can't disable security (already disabled)");
2937			error = 1;
2938		}
2939		break;
2940
2941	case ATA_SECURITY_ACTION_ERASE:
2942		if (security_enabled) {
2943			if (erase_timeout == 0) {
2944				erase_timeout = atasecurity_erase_timeout_msecs(
2945				    ident_buf->erase_time);
2946			}
2947
2948			error = atasecurity_erase(device, ccb, retry_count,
2949					          timeout, erase_timeout, &pwd,
2950						  quiet);
2951		} else {
2952			warnx("Can't secure erase (security is disabled)");
2953			error = 1;
2954		}
2955		break;
2956
2957	case ATA_SECURITY_ACTION_ERASE_ENHANCED:
2958		if (security_enabled) {
2959			if (ident_buf->security_status & ATA_SECURITY_ENH_SUPP) {
2960				if (erase_timeout == 0) {
2961					erase_timeout =
2962					    atasecurity_erase_timeout_msecs(
2963						ident_buf->enhanced_erase_time);
2964				}
2965
2966				error = atasecurity_erase(device, ccb,
2967							  retry_count, timeout,
2968							  erase_timeout, &pwd,
2969							  quiet);
2970			} else {
2971				warnx("Enhanced erase is not supported");
2972				error = 1;
2973			}
2974		} else {
2975			warnx("Can't secure erase (enhanced), "
2976			      "(security is disabled)");
2977			error = 1;
2978		}
2979		break;
2980	}
2981
2982	cam_freeccb(ccb);
2983	free(ident_buf);
2984
2985	return (error);
2986}
2987#endif /* MINIMALISTIC */
2988
2989/*
2990 * Parse out a bus, or a bus, target and lun in the following
2991 * format:
2992 * bus
2993 * bus:target
2994 * bus:target:lun
2995 *
2996 * Returns the number of parsed components, or 0.
2997 */
2998static int
2999parse_btl(char *tstr, int *bus, int *target, int *lun, cam_argmask *arglst)
3000{
3001	char *tmpstr;
3002	int convs = 0;
3003
3004	while (isspace(*tstr) && (*tstr != '\0'))
3005		tstr++;
3006
3007	tmpstr = (char *)strtok(tstr, ":");
3008	if ((tmpstr != NULL) && (*tmpstr != '\0')) {
3009		*bus = strtol(tmpstr, NULL, 0);
3010		*arglst |= CAM_ARG_BUS;
3011		convs++;
3012		tmpstr = (char *)strtok(NULL, ":");
3013		if ((tmpstr != NULL) && (*tmpstr != '\0')) {
3014			*target = strtol(tmpstr, NULL, 0);
3015			*arglst |= CAM_ARG_TARGET;
3016			convs++;
3017			tmpstr = (char *)strtok(NULL, ":");
3018			if ((tmpstr != NULL) && (*tmpstr != '\0')) {
3019				*lun = strtol(tmpstr, NULL, 0);
3020				*arglst |= CAM_ARG_LUN;
3021				convs++;
3022			}
3023		}
3024	}
3025
3026	return convs;
3027}
3028
3029static int
3030dorescan_or_reset(int argc, char **argv, int rescan)
3031{
3032	static const char must[] =
3033		"you must specify \"all\", a bus, or a bus:target:lun to %s";
3034	int rv, error = 0;
3035	int bus = -1, target = -1, lun = -1;
3036	char *tstr;
3037
3038	if (argc < 3) {
3039		warnx(must, rescan? "rescan" : "reset");
3040		return(1);
3041	}
3042
3043	tstr = argv[optind];
3044	while (isspace(*tstr) && (*tstr != '\0'))
3045		tstr++;
3046	if (strncasecmp(tstr, "all", strlen("all")) == 0)
3047		arglist |= CAM_ARG_BUS;
3048	else {
3049		rv = parse_btl(argv[optind], &bus, &target, &lun, &arglist);
3050		if (rv != 1 && rv != 3) {
3051			warnx(must, rescan? "rescan" : "reset");
3052			return(1);
3053		}
3054	}
3055
3056	if ((arglist & CAM_ARG_BUS)
3057	    && (arglist & CAM_ARG_TARGET)
3058	    && (arglist & CAM_ARG_LUN))
3059		error = scanlun_or_reset_dev(bus, target, lun, rescan);
3060	else
3061		error = rescan_or_reset_bus(bus, rescan);
3062
3063	return(error);
3064}
3065
3066static int
3067rescan_or_reset_bus(int bus, int rescan)
3068{
3069	union ccb ccb, matchccb;
3070	int fd, retval;
3071	int bufsize;
3072
3073	retval = 0;
3074
3075	if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
3076		warnx("error opening transport layer device %s", XPT_DEVICE);
3077		warn("%s", XPT_DEVICE);
3078		return(1);
3079	}
3080
3081	if (bus != -1) {
3082		ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS : XPT_RESET_BUS;
3083		ccb.ccb_h.path_id = bus;
3084		ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
3085		ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
3086		ccb.crcn.flags = CAM_FLAG_NONE;
3087
3088		/* run this at a low priority */
3089		ccb.ccb_h.pinfo.priority = 5;
3090
3091		if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
3092			warn("CAMIOCOMMAND ioctl failed");
3093			close(fd);
3094			return(1);
3095		}
3096
3097		if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
3098			fprintf(stdout, "%s of bus %d was successful\n",
3099			    rescan ? "Re-scan" : "Reset", bus);
3100		} else {
3101			fprintf(stdout, "%s of bus %d returned error %#x\n",
3102				rescan ? "Re-scan" : "Reset", bus,
3103				ccb.ccb_h.status & CAM_STATUS_MASK);
3104			retval = 1;
3105		}
3106
3107		close(fd);
3108		return(retval);
3109
3110	}
3111
3112
3113	/*
3114	 * The right way to handle this is to modify the xpt so that it can
3115	 * handle a wildcarded bus in a rescan or reset CCB.  At the moment
3116	 * that isn't implemented, so instead we enumerate the busses and
3117	 * send the rescan or reset to those busses in the case where the
3118	 * given bus is -1 (wildcard).  We don't send a rescan or reset
3119	 * to the xpt bus; sending a rescan to the xpt bus is effectively a
3120	 * no-op, sending a rescan to the xpt bus would result in a status of
3121	 * CAM_REQ_INVALID.
3122	 */
3123	bzero(&(&matchccb.ccb_h)[1],
3124	      sizeof(struct ccb_dev_match) - sizeof(struct ccb_hdr));
3125	matchccb.ccb_h.func_code = XPT_DEV_MATCH;
3126	matchccb.ccb_h.path_id = CAM_BUS_WILDCARD;
3127	bufsize = sizeof(struct dev_match_result) * 20;
3128	matchccb.cdm.match_buf_len = bufsize;
3129	matchccb.cdm.matches=(struct dev_match_result *)malloc(bufsize);
3130	if (matchccb.cdm.matches == NULL) {
3131		warnx("can't malloc memory for matches");
3132		retval = 1;
3133		goto bailout;
3134	}
3135	matchccb.cdm.num_matches = 0;
3136
3137	matchccb.cdm.num_patterns = 1;
3138	matchccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern);
3139
3140	matchccb.cdm.patterns = (struct dev_match_pattern *)malloc(
3141		matchccb.cdm.pattern_buf_len);
3142	if (matchccb.cdm.patterns == NULL) {
3143		warnx("can't malloc memory for patterns");
3144		retval = 1;
3145		goto bailout;
3146	}
3147	matchccb.cdm.patterns[0].type = DEV_MATCH_BUS;
3148	matchccb.cdm.patterns[0].pattern.bus_pattern.flags = BUS_MATCH_ANY;
3149
3150	do {
3151		unsigned int i;
3152
3153		if (ioctl(fd, CAMIOCOMMAND, &matchccb) == -1) {
3154			warn("CAMIOCOMMAND ioctl failed");
3155			retval = 1;
3156			goto bailout;
3157		}
3158
3159		if ((matchccb.ccb_h.status != CAM_REQ_CMP)
3160		 || ((matchccb.cdm.status != CAM_DEV_MATCH_LAST)
3161		   && (matchccb.cdm.status != CAM_DEV_MATCH_MORE))) {
3162			warnx("got CAM error %#x, CDM error %d\n",
3163			      matchccb.ccb_h.status, matchccb.cdm.status);
3164			retval = 1;
3165			goto bailout;
3166		}
3167
3168		for (i = 0; i < matchccb.cdm.num_matches; i++) {
3169			struct bus_match_result *bus_result;
3170
3171			/* This shouldn't happen. */
3172			if (matchccb.cdm.matches[i].type != DEV_MATCH_BUS)
3173				continue;
3174
3175			bus_result = &matchccb.cdm.matches[i].result.bus_result;
3176
3177			/*
3178			 * We don't want to rescan or reset the xpt bus.
3179			 * See above.
3180			 */
3181			if ((int)bus_result->path_id == -1)
3182				continue;
3183
3184			ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS :
3185						       XPT_RESET_BUS;
3186			ccb.ccb_h.path_id = bus_result->path_id;
3187			ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
3188			ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
3189			ccb.crcn.flags = CAM_FLAG_NONE;
3190
3191			/* run this at a low priority */
3192			ccb.ccb_h.pinfo.priority = 5;
3193
3194			if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
3195				warn("CAMIOCOMMAND ioctl failed");
3196				retval = 1;
3197				goto bailout;
3198			}
3199
3200			if ((ccb.ccb_h.status & CAM_STATUS_MASK) ==CAM_REQ_CMP){
3201				fprintf(stdout, "%s of bus %d was successful\n",
3202					rescan? "Re-scan" : "Reset",
3203					bus_result->path_id);
3204			} else {
3205				/*
3206				 * Don't bail out just yet, maybe the other
3207				 * rescan or reset commands will complete
3208				 * successfully.
3209				 */
3210				fprintf(stderr, "%s of bus %d returned error "
3211					"%#x\n", rescan? "Re-scan" : "Reset",
3212					bus_result->path_id,
3213					ccb.ccb_h.status & CAM_STATUS_MASK);
3214				retval = 1;
3215			}
3216		}
3217	} while ((matchccb.ccb_h.status == CAM_REQ_CMP)
3218		 && (matchccb.cdm.status == CAM_DEV_MATCH_MORE));
3219
3220bailout:
3221
3222	if (fd != -1)
3223		close(fd);
3224
3225	if (matchccb.cdm.patterns != NULL)
3226		free(matchccb.cdm.patterns);
3227	if (matchccb.cdm.matches != NULL)
3228		free(matchccb.cdm.matches);
3229
3230	return(retval);
3231}
3232
3233static int
3234scanlun_or_reset_dev(int bus, int target, int lun, int scan)
3235{
3236	union ccb ccb;
3237	struct cam_device *device;
3238	int fd;
3239
3240	device = NULL;
3241
3242	if (bus < 0) {
3243		warnx("invalid bus number %d", bus);
3244		return(1);
3245	}
3246
3247	if (target < 0) {
3248		warnx("invalid target number %d", target);
3249		return(1);
3250	}
3251
3252	if (lun < 0) {
3253		warnx("invalid lun number %d", lun);
3254		return(1);
3255	}
3256
3257	fd = -1;
3258
3259	bzero(&ccb, sizeof(union ccb));
3260
3261	if (scan) {
3262		if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
3263			warnx("error opening transport layer device %s\n",
3264			    XPT_DEVICE);
3265			warn("%s", XPT_DEVICE);
3266			return(1);
3267		}
3268	} else {
3269		device = cam_open_btl(bus, target, lun, O_RDWR, NULL);
3270		if (device == NULL) {
3271			warnx("%s", cam_errbuf);
3272			return(1);
3273		}
3274	}
3275
3276	ccb.ccb_h.func_code = (scan)? XPT_SCAN_LUN : XPT_RESET_DEV;
3277	ccb.ccb_h.path_id = bus;
3278	ccb.ccb_h.target_id = target;
3279	ccb.ccb_h.target_lun = lun;
3280	ccb.ccb_h.timeout = 5000;
3281	ccb.crcn.flags = CAM_FLAG_NONE;
3282
3283	/* run this at a low priority */
3284	ccb.ccb_h.pinfo.priority = 5;
3285
3286	if (scan) {
3287		if (ioctl(fd, CAMIOCOMMAND, &ccb) < 0) {
3288			warn("CAMIOCOMMAND ioctl failed");
3289			close(fd);
3290			return(1);
3291		}
3292	} else {
3293		if (cam_send_ccb(device, &ccb) < 0) {
3294			warn("error sending XPT_RESET_DEV CCB");
3295			cam_close_device(device);
3296			return(1);
3297		}
3298	}
3299
3300	if (scan)
3301		close(fd);
3302	else
3303		cam_close_device(device);
3304
3305	/*
3306	 * An error code of CAM_BDR_SENT is normal for a BDR request.
3307	 */
3308	if (((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
3309	 || ((!scan)
3310	  && ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_BDR_SENT))) {
3311		fprintf(stdout, "%s of %d:%d:%d was successful\n",
3312		    scan? "Re-scan" : "Reset", bus, target, lun);
3313		return(0);
3314	} else {
3315		fprintf(stdout, "%s of %d:%d:%d returned error %#x\n",
3316		    scan? "Re-scan" : "Reset", bus, target, lun,
3317		    ccb.ccb_h.status & CAM_STATUS_MASK);
3318		return(1);
3319	}
3320}
3321
3322#ifndef MINIMALISTIC
3323static int
3324readdefects(struct cam_device *device, int argc, char **argv,
3325	    char *combinedopt, int retry_count, int timeout)
3326{
3327	union ccb *ccb = NULL;
3328	struct scsi_read_defect_data_10 *rdd_cdb;
3329	u_int8_t *defect_list = NULL;
3330	u_int32_t max_dlist_length = SRDD10_MAX_LENGTH, dlist_length = 0;
3331	u_int32_t returned_length = 0;
3332	u_int32_t num_returned = 0;
3333	u_int8_t returned_format;
3334	unsigned int i;
3335	int c, error = 0;
3336	int lists_specified;
3337	int get_length = 1;
3338
3339	while ((c = getopt(argc, argv, combinedopt)) != -1) {
3340		switch(c){
3341		case 'f':
3342		{
3343			char *tstr;
3344			tstr = optarg;
3345			while (isspace(*tstr) && (*tstr != '\0'))
3346				tstr++;
3347			if (strcmp(tstr, "block") == 0)
3348				arglist |= CAM_ARG_FORMAT_BLOCK;
3349			else if (strcmp(tstr, "bfi") == 0)
3350				arglist |= CAM_ARG_FORMAT_BFI;
3351			else if (strcmp(tstr, "phys") == 0)
3352				arglist |= CAM_ARG_FORMAT_PHYS;
3353			else {
3354				error = 1;
3355				warnx("invalid defect format %s", tstr);
3356				goto defect_bailout;
3357			}
3358			break;
3359		}
3360		case 'G':
3361			arglist |= CAM_ARG_GLIST;
3362			break;
3363		case 'P':
3364			arglist |= CAM_ARG_PLIST;
3365			break;
3366		default:
3367			break;
3368		}
3369	}
3370
3371	ccb = cam_getccb(device);
3372
3373	/*
3374	 * Eventually we should probably support the 12 byte READ DEFECT
3375	 * DATA command.  It supports a longer parameter list, which may be
3376	 * necessary on newer drives with lots of defects.  According to
3377	 * the SBC-3 spec, drives are supposed to return an illegal request
3378	 * if they have more defect data than will fit in 64K.
3379	 */
3380	defect_list = malloc(max_dlist_length);
3381	if (defect_list == NULL) {
3382		warnx("can't malloc memory for defect list");
3383		error = 1;
3384		goto defect_bailout;
3385	}
3386
3387	/*
3388	 * We start off asking for just the header to determine how much
3389	 * defect data is available.  Some Hitachi drives return an error
3390	 * if you ask for more data than the drive has.  Once we know the
3391	 * length, we retry the command with the returned length.
3392	 */
3393	dlist_length = sizeof(struct scsi_read_defect_data_hdr_10);
3394
3395	rdd_cdb =(struct scsi_read_defect_data_10 *)&ccb->csio.cdb_io.cdb_bytes;
3396
3397retry:
3398
3399	lists_specified = 0;
3400
3401	/*
3402	 * cam_getccb() zeros the CCB header only.  So we need to zero the
3403	 * payload portion of the ccb.
3404	 */
3405	bzero(&(&ccb->ccb_h)[1],
3406	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
3407
3408	cam_fill_csio(&ccb->csio,
3409		      /*retries*/ retry_count,
3410		      /*cbfcnp*/ NULL,
3411		      /*flags*/ CAM_DIR_IN | ((arglist & CAM_ARG_ERR_RECOVER) ?
3412					      CAM_PASS_ERR_RECOVER : 0),
3413		      /*tag_action*/ MSG_SIMPLE_Q_TAG,
3414		      /*data_ptr*/ defect_list,
3415		      /*dxfer_len*/ dlist_length,
3416		      /*sense_len*/ SSD_FULL_SIZE,
3417		      /*cdb_len*/ sizeof(struct scsi_read_defect_data_10),
3418		      /*timeout*/ timeout ? timeout : 5000);
3419
3420	rdd_cdb->opcode = READ_DEFECT_DATA_10;
3421	if (arglist & CAM_ARG_FORMAT_BLOCK)
3422		rdd_cdb->format = SRDD10_BLOCK_FORMAT;
3423	else if (arglist & CAM_ARG_FORMAT_BFI)
3424		rdd_cdb->format = SRDD10_BYTES_FROM_INDEX_FORMAT;
3425	else if (arglist & CAM_ARG_FORMAT_PHYS)
3426		rdd_cdb->format = SRDD10_PHYSICAL_SECTOR_FORMAT;
3427	else {
3428		error = 1;
3429		warnx("no defect list format specified");
3430		goto defect_bailout;
3431	}
3432	if (arglist & CAM_ARG_PLIST) {
3433		rdd_cdb->format |= SRDD10_PLIST;
3434		lists_specified++;
3435	}
3436
3437	if (arglist & CAM_ARG_GLIST) {
3438		rdd_cdb->format |= SRDD10_GLIST;
3439		lists_specified++;
3440	}
3441
3442	scsi_ulto2b(dlist_length, rdd_cdb->alloc_length);
3443
3444	/* Disable freezing the device queue */
3445	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
3446
3447	if (cam_send_ccb(device, ccb) < 0) {
3448		perror("error reading defect list");
3449
3450		if (arglist & CAM_ARG_VERBOSE) {
3451			cam_error_print(device, ccb, CAM_ESF_ALL,
3452					CAM_EPF_ALL, stderr);
3453		}
3454
3455		error = 1;
3456		goto defect_bailout;
3457	}
3458
3459	returned_length = scsi_2btoul(((struct
3460		scsi_read_defect_data_hdr_10 *)defect_list)->length);
3461
3462	if (get_length != 0) {
3463		get_length = 0;
3464
3465		if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
3466		     CAM_SCSI_STATUS_ERROR) {
3467			struct scsi_sense_data *sense;
3468			int error_code, sense_key, asc, ascq;
3469
3470			sense = &ccb->csio.sense_data;
3471			scsi_extract_sense_len(sense, ccb->csio.sense_len -
3472			    ccb->csio.sense_resid, &error_code, &sense_key,
3473			    &asc, &ascq, /*show_errors*/ 1);
3474
3475			/*
3476			 * If the drive is reporting that it just doesn't
3477			 * support the defect list format, go ahead and use
3478			 * the length it reported.  Otherwise, the length
3479			 * may not be valid, so use the maximum.
3480			 */
3481			if ((sense_key == SSD_KEY_RECOVERED_ERROR)
3482			 && (asc == 0x1c) && (ascq == 0x00)
3483			 && (returned_length > 0)) {
3484				dlist_length = returned_length +
3485				    sizeof(struct scsi_read_defect_data_hdr_10);
3486				dlist_length = min(dlist_length,
3487						   SRDD10_MAX_LENGTH);
3488			} else
3489				dlist_length = max_dlist_length;
3490		} else if ((ccb->ccb_h.status & CAM_STATUS_MASK) !=
3491			    CAM_REQ_CMP){
3492			error = 1;
3493			warnx("Error reading defect header");
3494			if (arglist & CAM_ARG_VERBOSE)
3495				cam_error_print(device, ccb, CAM_ESF_ALL,
3496						CAM_EPF_ALL, stderr);
3497			goto defect_bailout;
3498		} else {
3499			dlist_length = returned_length +
3500			    sizeof(struct scsi_read_defect_data_hdr_10);
3501			dlist_length = min(dlist_length, SRDD10_MAX_LENGTH);
3502		}
3503
3504		goto retry;
3505	}
3506
3507	returned_format = ((struct scsi_read_defect_data_hdr_10 *)
3508			defect_list)->format;
3509
3510	if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR)
3511	 && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
3512	 && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) {
3513		struct scsi_sense_data *sense;
3514		int error_code, sense_key, asc, ascq;
3515
3516		sense = &ccb->csio.sense_data;
3517		scsi_extract_sense_len(sense, ccb->csio.sense_len -
3518		    ccb->csio.sense_resid, &error_code, &sense_key, &asc,
3519		    &ascq, /*show_errors*/ 1);
3520
3521		/*
3522		 * According to the SCSI spec, if the disk doesn't support
3523		 * the requested format, it will generally return a sense
3524		 * key of RECOVERED ERROR, and an additional sense code
3525		 * of "DEFECT LIST NOT FOUND".  So, we check for that, and
3526		 * also check to make sure that the returned length is
3527		 * greater than 0, and then print out whatever format the
3528		 * disk gave us.
3529		 */
3530		if ((sense_key == SSD_KEY_RECOVERED_ERROR)
3531		 && (asc == 0x1c) && (ascq == 0x00)
3532		 && (returned_length > 0)) {
3533			warnx("requested defect format not available");
3534			switch(returned_format & SRDDH10_DLIST_FORMAT_MASK) {
3535			case SRDD10_BLOCK_FORMAT:
3536				warnx("Device returned block format");
3537				break;
3538			case SRDD10_BYTES_FROM_INDEX_FORMAT:
3539				warnx("Device returned bytes from index"
3540				      " format");
3541				break;
3542			case SRDD10_PHYSICAL_SECTOR_FORMAT:
3543				warnx("Device returned physical sector format");
3544				break;
3545			default:
3546				error = 1;
3547				warnx("Device returned unknown defect"
3548				     " data format %#x", returned_format);
3549				goto defect_bailout;
3550				break; /* NOTREACHED */
3551			}
3552		} else {
3553			error = 1;
3554			warnx("Error returned from read defect data command");
3555			if (arglist & CAM_ARG_VERBOSE)
3556				cam_error_print(device, ccb, CAM_ESF_ALL,
3557						CAM_EPF_ALL, stderr);
3558			goto defect_bailout;
3559		}
3560	} else if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3561		error = 1;
3562		warnx("Error returned from read defect data command");
3563		if (arglist & CAM_ARG_VERBOSE)
3564			cam_error_print(device, ccb, CAM_ESF_ALL,
3565					CAM_EPF_ALL, stderr);
3566		goto defect_bailout;
3567	}
3568
3569	/*
3570	 * XXX KDM  I should probably clean up the printout format for the
3571	 * disk defects.
3572	 */
3573	switch (returned_format & SRDDH10_DLIST_FORMAT_MASK){
3574		case SRDDH10_PHYSICAL_SECTOR_FORMAT:
3575		{
3576			struct scsi_defect_desc_phys_sector *dlist;
3577
3578			dlist = (struct scsi_defect_desc_phys_sector *)
3579				(defect_list +
3580				sizeof(struct scsi_read_defect_data_hdr_10));
3581
3582			num_returned = returned_length /
3583				sizeof(struct scsi_defect_desc_phys_sector);
3584
3585			fprintf(stderr, "Got %d defect", num_returned);
3586
3587			if ((lists_specified == 0) || (num_returned == 0)) {
3588				fprintf(stderr, "s.\n");
3589				break;
3590			} else if (num_returned == 1)
3591				fprintf(stderr, ":\n");
3592			else
3593				fprintf(stderr, "s:\n");
3594
3595			for (i = 0; i < num_returned; i++) {
3596				fprintf(stdout, "%d:%d:%d\n",
3597					scsi_3btoul(dlist[i].cylinder),
3598					dlist[i].head,
3599					scsi_4btoul(dlist[i].sector));
3600			}
3601			break;
3602		}
3603		case SRDDH10_BYTES_FROM_INDEX_FORMAT:
3604		{
3605			struct scsi_defect_desc_bytes_from_index *dlist;
3606
3607			dlist = (struct scsi_defect_desc_bytes_from_index *)
3608				(defect_list +
3609				sizeof(struct scsi_read_defect_data_hdr_10));
3610
3611			num_returned = returned_length /
3612			      sizeof(struct scsi_defect_desc_bytes_from_index);
3613
3614			fprintf(stderr, "Got %d defect", num_returned);
3615
3616			if ((lists_specified == 0) || (num_returned == 0)) {
3617				fprintf(stderr, "s.\n");
3618				break;
3619			} else if (num_returned == 1)
3620				fprintf(stderr, ":\n");
3621			else
3622				fprintf(stderr, "s:\n");
3623
3624			for (i = 0; i < num_returned; i++) {
3625				fprintf(stdout, "%d:%d:%d\n",
3626					scsi_3btoul(dlist[i].cylinder),
3627					dlist[i].head,
3628					scsi_4btoul(dlist[i].bytes_from_index));
3629			}
3630			break;
3631		}
3632		case SRDDH10_BLOCK_FORMAT:
3633		{
3634			struct scsi_defect_desc_block *dlist;
3635
3636			dlist = (struct scsi_defect_desc_block *)(defect_list +
3637				sizeof(struct scsi_read_defect_data_hdr_10));
3638
3639			num_returned = returned_length /
3640			      sizeof(struct scsi_defect_desc_block);
3641
3642			fprintf(stderr, "Got %d defect", num_returned);
3643
3644			if ((lists_specified == 0) || (num_returned == 0)) {
3645				fprintf(stderr, "s.\n");
3646				break;
3647			} else if (num_returned == 1)
3648				fprintf(stderr, ":\n");
3649			else
3650				fprintf(stderr, "s:\n");
3651
3652			for (i = 0; i < num_returned; i++)
3653				fprintf(stdout, "%u\n",
3654					scsi_4btoul(dlist[i].address));
3655			break;
3656		}
3657		default:
3658			fprintf(stderr, "Unknown defect format %d\n",
3659				returned_format & SRDDH10_DLIST_FORMAT_MASK);
3660			error = 1;
3661			break;
3662	}
3663defect_bailout:
3664
3665	if (defect_list != NULL)
3666		free(defect_list);
3667
3668	if (ccb != NULL)
3669		cam_freeccb(ccb);
3670
3671	return(error);
3672}
3673#endif /* MINIMALISTIC */
3674
3675#if 0
3676void
3677reassignblocks(struct cam_device *device, u_int32_t *blocks, int num_blocks)
3678{
3679	union ccb *ccb;
3680
3681	ccb = cam_getccb(device);
3682
3683	cam_freeccb(ccb);
3684}
3685#endif
3686
3687#ifndef MINIMALISTIC
3688void
3689mode_sense(struct cam_device *device, int mode_page, int page_control,
3690	   int dbd, int retry_count, int timeout, u_int8_t *data, int datalen)
3691{
3692	union ccb *ccb;
3693	int retval;
3694
3695	ccb = cam_getccb(device);
3696
3697	if (ccb == NULL)
3698		errx(1, "mode_sense: couldn't allocate CCB");
3699
3700	bzero(&(&ccb->ccb_h)[1],
3701	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
3702
3703	scsi_mode_sense(&ccb->csio,
3704			/* retries */ retry_count,
3705			/* cbfcnp */ NULL,
3706			/* tag_action */ MSG_SIMPLE_Q_TAG,
3707			/* dbd */ dbd,
3708			/* page_code */ page_control << 6,
3709			/* page */ mode_page,
3710			/* param_buf */ data,
3711			/* param_len */ datalen,
3712			/* sense_len */ SSD_FULL_SIZE,
3713			/* timeout */ timeout ? timeout : 5000);
3714
3715	if (arglist & CAM_ARG_ERR_RECOVER)
3716		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
3717
3718	/* Disable freezing the device queue */
3719	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
3720
3721	if (((retval = cam_send_ccb(device, ccb)) < 0)
3722	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
3723		if (arglist & CAM_ARG_VERBOSE) {
3724			cam_error_print(device, ccb, CAM_ESF_ALL,
3725					CAM_EPF_ALL, stderr);
3726		}
3727		cam_freeccb(ccb);
3728		cam_close_device(device);
3729		if (retval < 0)
3730			err(1, "error sending mode sense command");
3731		else
3732			errx(1, "error sending mode sense command");
3733	}
3734
3735	cam_freeccb(ccb);
3736}
3737
3738void
3739mode_select(struct cam_device *device, int save_pages, int retry_count,
3740	   int timeout, u_int8_t *data, int datalen)
3741{
3742	union ccb *ccb;
3743	int retval;
3744
3745	ccb = cam_getccb(device);
3746
3747	if (ccb == NULL)
3748		errx(1, "mode_select: couldn't allocate CCB");
3749
3750	bzero(&(&ccb->ccb_h)[1],
3751	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
3752
3753	scsi_mode_select(&ccb->csio,
3754			 /* retries */ retry_count,
3755			 /* cbfcnp */ NULL,
3756			 /* tag_action */ MSG_SIMPLE_Q_TAG,
3757			 /* scsi_page_fmt */ 1,
3758			 /* save_pages */ save_pages,
3759			 /* param_buf */ data,
3760			 /* param_len */ datalen,
3761			 /* sense_len */ SSD_FULL_SIZE,
3762			 /* timeout */ timeout ? timeout : 5000);
3763
3764	if (arglist & CAM_ARG_ERR_RECOVER)
3765		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
3766
3767	/* Disable freezing the device queue */
3768	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
3769
3770	if (((retval = cam_send_ccb(device, ccb)) < 0)
3771	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
3772		if (arglist & CAM_ARG_VERBOSE) {
3773			cam_error_print(device, ccb, CAM_ESF_ALL,
3774					CAM_EPF_ALL, stderr);
3775		}
3776		cam_freeccb(ccb);
3777		cam_close_device(device);
3778
3779		if (retval < 0)
3780			err(1, "error sending mode select command");
3781		else
3782			errx(1, "error sending mode select command");
3783
3784	}
3785
3786	cam_freeccb(ccb);
3787}
3788
3789void
3790modepage(struct cam_device *device, int argc, char **argv, char *combinedopt,
3791	 int retry_count, int timeout)
3792{
3793	int c, mode_page = -1, page_control = 0;
3794	int binary = 0, list = 0;
3795
3796	while ((c = getopt(argc, argv, combinedopt)) != -1) {
3797		switch(c) {
3798		case 'b':
3799			binary = 1;
3800			break;
3801		case 'd':
3802			arglist |= CAM_ARG_DBD;
3803			break;
3804		case 'e':
3805			arglist |= CAM_ARG_MODE_EDIT;
3806			break;
3807		case 'l':
3808			list = 1;
3809			break;
3810		case 'm':
3811			mode_page = strtol(optarg, NULL, 0);
3812			if (mode_page < 0)
3813				errx(1, "invalid mode page %d", mode_page);
3814			break;
3815		case 'P':
3816			page_control = strtol(optarg, NULL, 0);
3817			if ((page_control < 0) || (page_control > 3))
3818				errx(1, "invalid page control field %d",
3819				     page_control);
3820			arglist |= CAM_ARG_PAGE_CNTL;
3821			break;
3822		default:
3823			break;
3824		}
3825	}
3826
3827	if (mode_page == -1 && list == 0)
3828		errx(1, "you must specify a mode page!");
3829
3830	if (list) {
3831		mode_list(device, page_control, arglist & CAM_ARG_DBD,
3832		    retry_count, timeout);
3833	} else {
3834		mode_edit(device, mode_page, page_control,
3835		    arglist & CAM_ARG_DBD, arglist & CAM_ARG_MODE_EDIT, binary,
3836		    retry_count, timeout);
3837	}
3838}
3839
3840static int
3841scsicmd(struct cam_device *device, int argc, char **argv, char *combinedopt,
3842	int retry_count, int timeout)
3843{
3844	union ccb *ccb;
3845	u_int32_t flags = CAM_DIR_NONE;
3846	u_int8_t *data_ptr = NULL;
3847	u_int8_t cdb[20];
3848	u_int8_t atacmd[12];
3849	struct get_hook hook;
3850	int c, data_bytes = 0;
3851	int cdb_len = 0;
3852	int atacmd_len = 0;
3853	int dmacmd = 0;
3854	int fpdmacmd = 0;
3855	int need_res = 0;
3856	char *datastr = NULL, *tstr, *resstr = NULL;
3857	int error = 0;
3858	int fd_data = 0, fd_res = 0;
3859	int retval;
3860
3861	ccb = cam_getccb(device);
3862
3863	if (ccb == NULL) {
3864		warnx("scsicmd: error allocating ccb");
3865		return(1);
3866	}
3867
3868	bzero(&(&ccb->ccb_h)[1],
3869	      sizeof(union ccb) - sizeof(struct ccb_hdr));
3870
3871	while ((c = getopt(argc, argv, combinedopt)) != -1) {
3872		switch(c) {
3873		case 'a':
3874			tstr = optarg;
3875			while (isspace(*tstr) && (*tstr != '\0'))
3876				tstr++;
3877			hook.argc = argc - optind;
3878			hook.argv = argv + optind;
3879			hook.got = 0;
3880			atacmd_len = buff_encode_visit(atacmd, sizeof(atacmd), tstr,
3881						    iget, &hook);
3882			/*
3883			 * Increment optind by the number of arguments the
3884			 * encoding routine processed.  After each call to
3885			 * getopt(3), optind points to the argument that
3886			 * getopt should process _next_.  In this case,
3887			 * that means it points to the first command string
3888			 * argument, if there is one.  Once we increment
3889			 * this, it should point to either the next command
3890			 * line argument, or it should be past the end of
3891			 * the list.
3892			 */
3893			optind += hook.got;
3894			break;
3895		case 'c':
3896			tstr = optarg;
3897			while (isspace(*tstr) && (*tstr != '\0'))
3898				tstr++;
3899			hook.argc = argc - optind;
3900			hook.argv = argv + optind;
3901			hook.got = 0;
3902			cdb_len = buff_encode_visit(cdb, sizeof(cdb), tstr,
3903						    iget, &hook);
3904			/*
3905			 * Increment optind by the number of arguments the
3906			 * encoding routine processed.  After each call to
3907			 * getopt(3), optind points to the argument that
3908			 * getopt should process _next_.  In this case,
3909			 * that means it points to the first command string
3910			 * argument, if there is one.  Once we increment
3911			 * this, it should point to either the next command
3912			 * line argument, or it should be past the end of
3913			 * the list.
3914			 */
3915			optind += hook.got;
3916			break;
3917		case 'd':
3918			dmacmd = 1;
3919			break;
3920		case 'f':
3921			fpdmacmd = 1;
3922			break;
3923		case 'i':
3924			if (arglist & CAM_ARG_CMD_OUT) {
3925				warnx("command must either be "
3926				      "read or write, not both");
3927				error = 1;
3928				goto scsicmd_bailout;
3929			}
3930			arglist |= CAM_ARG_CMD_IN;
3931			flags = CAM_DIR_IN;
3932			data_bytes = strtol(optarg, NULL, 0);
3933			if (data_bytes <= 0) {
3934				warnx("invalid number of input bytes %d",
3935				      data_bytes);
3936				error = 1;
3937				goto scsicmd_bailout;
3938			}
3939			hook.argc = argc - optind;
3940			hook.argv = argv + optind;
3941			hook.got = 0;
3942			optind++;
3943			datastr = cget(&hook, NULL);
3944			/*
3945			 * If the user supplied "-" instead of a format, he
3946			 * wants the data to be written to stdout.
3947			 */
3948			if ((datastr != NULL)
3949			 && (datastr[0] == '-'))
3950				fd_data = 1;
3951
3952			data_ptr = (u_int8_t *)malloc(data_bytes);
3953			if (data_ptr == NULL) {
3954				warnx("can't malloc memory for data_ptr");
3955				error = 1;
3956				goto scsicmd_bailout;
3957			}
3958			break;
3959		case 'o':
3960			if (arglist & CAM_ARG_CMD_IN) {
3961				warnx("command must either be "
3962				      "read or write, not both");
3963				error = 1;
3964				goto scsicmd_bailout;
3965			}
3966			arglist |= CAM_ARG_CMD_OUT;
3967			flags = CAM_DIR_OUT;
3968			data_bytes = strtol(optarg, NULL, 0);
3969			if (data_bytes <= 0) {
3970				warnx("invalid number of output bytes %d",
3971				      data_bytes);
3972				error = 1;
3973				goto scsicmd_bailout;
3974			}
3975			hook.argc = argc - optind;
3976			hook.argv = argv + optind;
3977			hook.got = 0;
3978			datastr = cget(&hook, NULL);
3979			data_ptr = (u_int8_t *)malloc(data_bytes);
3980			if (data_ptr == NULL) {
3981				warnx("can't malloc memory for data_ptr");
3982				error = 1;
3983				goto scsicmd_bailout;
3984			}
3985			bzero(data_ptr, data_bytes);
3986			/*
3987			 * If the user supplied "-" instead of a format, he
3988			 * wants the data to be read from stdin.
3989			 */
3990			if ((datastr != NULL)
3991			 && (datastr[0] == '-'))
3992				fd_data = 1;
3993			else
3994				buff_encode_visit(data_ptr, data_bytes, datastr,
3995						  iget, &hook);
3996			optind += hook.got;
3997			break;
3998		case 'r':
3999			need_res = 1;
4000			hook.argc = argc - optind;
4001			hook.argv = argv + optind;
4002			hook.got = 0;
4003			resstr = cget(&hook, NULL);
4004			if ((resstr != NULL) && (resstr[0] == '-'))
4005				fd_res = 1;
4006			optind += hook.got;
4007			break;
4008		default:
4009			break;
4010		}
4011	}
4012
4013	/*
4014	 * If fd_data is set, and we're writing to the device, we need to
4015	 * read the data the user wants written from stdin.
4016	 */
4017	if ((fd_data == 1) && (arglist & CAM_ARG_CMD_OUT)) {
4018		ssize_t amt_read;
4019		int amt_to_read = data_bytes;
4020		u_int8_t *buf_ptr = data_ptr;
4021
4022		for (amt_read = 0; amt_to_read > 0;
4023		     amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) {
4024			if (amt_read == -1) {
4025				warn("error reading data from stdin");
4026				error = 1;
4027				goto scsicmd_bailout;
4028			}
4029			amt_to_read -= amt_read;
4030			buf_ptr += amt_read;
4031		}
4032	}
4033
4034	if (arglist & CAM_ARG_ERR_RECOVER)
4035		flags |= CAM_PASS_ERR_RECOVER;
4036
4037	/* Disable freezing the device queue */
4038	flags |= CAM_DEV_QFRZDIS;
4039
4040	if (cdb_len) {
4041		/*
4042		 * This is taken from the SCSI-3 draft spec.
4043		 * (T10/1157D revision 0.3)
4044		 * The top 3 bits of an opcode are the group code.
4045		 * The next 5 bits are the command code.
4046		 * Group 0:  six byte commands
4047		 * Group 1:  ten byte commands
4048		 * Group 2:  ten byte commands
4049		 * Group 3:  reserved
4050		 * Group 4:  sixteen byte commands
4051		 * Group 5:  twelve byte commands
4052		 * Group 6:  vendor specific
4053		 * Group 7:  vendor specific
4054		 */
4055		switch((cdb[0] >> 5) & 0x7) {
4056			case 0:
4057				cdb_len = 6;
4058				break;
4059			case 1:
4060			case 2:
4061				cdb_len = 10;
4062				break;
4063			case 3:
4064			case 6:
4065			case 7:
4066			        /* computed by buff_encode_visit */
4067				break;
4068			case 4:
4069				cdb_len = 16;
4070				break;
4071			case 5:
4072				cdb_len = 12;
4073				break;
4074		}
4075
4076		/*
4077		 * We should probably use csio_build_visit or something like that
4078		 * here, but it's easier to encode arguments as you go.  The
4079		 * alternative would be skipping the CDB argument and then encoding
4080		 * it here, since we've got the data buffer argument by now.
4081		 */
4082		bcopy(cdb, &ccb->csio.cdb_io.cdb_bytes, cdb_len);
4083
4084		cam_fill_csio(&ccb->csio,
4085		      /*retries*/ retry_count,
4086		      /*cbfcnp*/ NULL,
4087		      /*flags*/ flags,
4088		      /*tag_action*/ MSG_SIMPLE_Q_TAG,
4089		      /*data_ptr*/ data_ptr,
4090		      /*dxfer_len*/ data_bytes,
4091		      /*sense_len*/ SSD_FULL_SIZE,
4092		      /*cdb_len*/ cdb_len,
4093		      /*timeout*/ timeout ? timeout : 5000);
4094	} else {
4095		atacmd_len = 12;
4096		bcopy(atacmd, &ccb->ataio.cmd.command, atacmd_len);
4097		if (need_res)
4098			ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT;
4099		if (dmacmd)
4100			ccb->ataio.cmd.flags |= CAM_ATAIO_DMA;
4101		if (fpdmacmd)
4102			ccb->ataio.cmd.flags |= CAM_ATAIO_FPDMA;
4103
4104		cam_fill_ataio(&ccb->ataio,
4105		      /*retries*/ retry_count,
4106		      /*cbfcnp*/ NULL,
4107		      /*flags*/ flags,
4108		      /*tag_action*/ 0,
4109		      /*data_ptr*/ data_ptr,
4110		      /*dxfer_len*/ data_bytes,
4111		      /*timeout*/ timeout ? timeout : 5000);
4112	}
4113
4114	if (((retval = cam_send_ccb(device, ccb)) < 0)
4115	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
4116		const char warnstr[] = "error sending command";
4117
4118		if (retval < 0)
4119			warn(warnstr);
4120		else
4121			warnx(warnstr);
4122
4123		if (arglist & CAM_ARG_VERBOSE) {
4124			cam_error_print(device, ccb, CAM_ESF_ALL,
4125					CAM_EPF_ALL, stderr);
4126		}
4127
4128		error = 1;
4129		goto scsicmd_bailout;
4130	}
4131
4132	if (atacmd_len && need_res) {
4133		if (fd_res == 0) {
4134			buff_decode_visit(&ccb->ataio.res.status, 11, resstr,
4135					  arg_put, NULL);
4136			fprintf(stdout, "\n");
4137		} else {
4138			fprintf(stdout,
4139			    "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
4140			    ccb->ataio.res.status,
4141			    ccb->ataio.res.error,
4142			    ccb->ataio.res.lba_low,
4143			    ccb->ataio.res.lba_mid,
4144			    ccb->ataio.res.lba_high,
4145			    ccb->ataio.res.device,
4146			    ccb->ataio.res.lba_low_exp,
4147			    ccb->ataio.res.lba_mid_exp,
4148			    ccb->ataio.res.lba_high_exp,
4149			    ccb->ataio.res.sector_count,
4150			    ccb->ataio.res.sector_count_exp);
4151			fflush(stdout);
4152		}
4153	}
4154
4155	if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
4156	 && (arglist & CAM_ARG_CMD_IN)
4157	 && (data_bytes > 0)) {
4158		if (fd_data == 0) {
4159			buff_decode_visit(data_ptr, data_bytes, datastr,
4160					  arg_put, NULL);
4161			fprintf(stdout, "\n");
4162		} else {
4163			ssize_t amt_written;
4164			int amt_to_write = data_bytes;
4165			u_int8_t *buf_ptr = data_ptr;
4166
4167			for (amt_written = 0; (amt_to_write > 0) &&
4168			     (amt_written =write(1, buf_ptr,amt_to_write))> 0;){
4169				amt_to_write -= amt_written;
4170				buf_ptr += amt_written;
4171			}
4172			if (amt_written == -1) {
4173				warn("error writing data to stdout");
4174				error = 1;
4175				goto scsicmd_bailout;
4176			} else if ((amt_written == 0)
4177				&& (amt_to_write > 0)) {
4178				warnx("only wrote %u bytes out of %u",
4179				      data_bytes - amt_to_write, data_bytes);
4180			}
4181		}
4182	}
4183
4184scsicmd_bailout:
4185
4186	if ((data_bytes > 0) && (data_ptr != NULL))
4187		free(data_ptr);
4188
4189	cam_freeccb(ccb);
4190
4191	return(error);
4192}
4193
4194static int
4195camdebug(int argc, char **argv, char *combinedopt)
4196{
4197	int c, fd;
4198	int bus = -1, target = -1, lun = -1;
4199	char *tstr, *tmpstr = NULL;
4200	union ccb ccb;
4201	int error = 0;
4202
4203	bzero(&ccb, sizeof(union ccb));
4204
4205	while ((c = getopt(argc, argv, combinedopt)) != -1) {
4206		switch(c) {
4207		case 'I':
4208			arglist |= CAM_ARG_DEBUG_INFO;
4209			ccb.cdbg.flags |= CAM_DEBUG_INFO;
4210			break;
4211		case 'P':
4212			arglist |= CAM_ARG_DEBUG_PERIPH;
4213			ccb.cdbg.flags |= CAM_DEBUG_PERIPH;
4214			break;
4215		case 'S':
4216			arglist |= CAM_ARG_DEBUG_SUBTRACE;
4217			ccb.cdbg.flags |= CAM_DEBUG_SUBTRACE;
4218			break;
4219		case 'T':
4220			arglist |= CAM_ARG_DEBUG_TRACE;
4221			ccb.cdbg.flags |= CAM_DEBUG_TRACE;
4222			break;
4223		case 'X':
4224			arglist |= CAM_ARG_DEBUG_XPT;
4225			ccb.cdbg.flags |= CAM_DEBUG_XPT;
4226			break;
4227		case 'c':
4228			arglist |= CAM_ARG_DEBUG_CDB;
4229			ccb.cdbg.flags |= CAM_DEBUG_CDB;
4230			break;
4231		case 'p':
4232			arglist |= CAM_ARG_DEBUG_PROBE;
4233			ccb.cdbg.flags |= CAM_DEBUG_PROBE;
4234			break;
4235		default:
4236			break;
4237		}
4238	}
4239
4240	if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
4241		warnx("error opening transport layer device %s", XPT_DEVICE);
4242		warn("%s", XPT_DEVICE);
4243		return(1);
4244	}
4245	argc -= optind;
4246	argv += optind;
4247
4248	if (argc <= 0) {
4249		warnx("you must specify \"off\", \"all\" or a bus,");
4250		warnx("bus:target, or bus:target:lun");
4251		close(fd);
4252		return(1);
4253	}
4254
4255	tstr = *argv;
4256
4257	while (isspace(*tstr) && (*tstr != '\0'))
4258		tstr++;
4259
4260	if (strncmp(tstr, "off", 3) == 0) {
4261		ccb.cdbg.flags = CAM_DEBUG_NONE;
4262		arglist &= ~(CAM_ARG_DEBUG_INFO|CAM_ARG_DEBUG_PERIPH|
4263			     CAM_ARG_DEBUG_TRACE|CAM_ARG_DEBUG_SUBTRACE|
4264			     CAM_ARG_DEBUG_XPT|CAM_ARG_DEBUG_PROBE);
4265	} else if (strncmp(tstr, "all", 3) != 0) {
4266		tmpstr = (char *)strtok(tstr, ":");
4267		if ((tmpstr != NULL) && (*tmpstr != '\0')){
4268			bus = strtol(tmpstr, NULL, 0);
4269			arglist |= CAM_ARG_BUS;
4270			tmpstr = (char *)strtok(NULL, ":");
4271			if ((tmpstr != NULL) && (*tmpstr != '\0')){
4272				target = strtol(tmpstr, NULL, 0);
4273				arglist |= CAM_ARG_TARGET;
4274				tmpstr = (char *)strtok(NULL, ":");
4275				if ((tmpstr != NULL) && (*tmpstr != '\0')){
4276					lun = strtol(tmpstr, NULL, 0);
4277					arglist |= CAM_ARG_LUN;
4278				}
4279			}
4280		} else {
4281			error = 1;
4282			warnx("you must specify \"all\", \"off\", or a bus,");
4283			warnx("bus:target, or bus:target:lun to debug");
4284		}
4285	}
4286
4287	if (error == 0) {
4288
4289		ccb.ccb_h.func_code = XPT_DEBUG;
4290		ccb.ccb_h.path_id = bus;
4291		ccb.ccb_h.target_id = target;
4292		ccb.ccb_h.target_lun = lun;
4293
4294		if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
4295			warn("CAMIOCOMMAND ioctl failed");
4296			error = 1;
4297		}
4298
4299		if (error == 0) {
4300			if ((ccb.ccb_h.status & CAM_STATUS_MASK) ==
4301			     CAM_FUNC_NOTAVAIL) {
4302				warnx("CAM debugging not available");
4303				warnx("you need to put options CAMDEBUG in"
4304				      " your kernel config file!");
4305				error = 1;
4306			} else if ((ccb.ccb_h.status & CAM_STATUS_MASK) !=
4307				    CAM_REQ_CMP) {
4308				warnx("XPT_DEBUG CCB failed with status %#x",
4309				      ccb.ccb_h.status);
4310				error = 1;
4311			} else {
4312				if (ccb.cdbg.flags == CAM_DEBUG_NONE) {
4313					fprintf(stderr,
4314						"Debugging turned off\n");
4315				} else {
4316					fprintf(stderr,
4317						"Debugging enabled for "
4318						"%d:%d:%d\n",
4319						bus, target, lun);
4320				}
4321			}
4322		}
4323		close(fd);
4324	}
4325
4326	return(error);
4327}
4328
4329static int
4330tagcontrol(struct cam_device *device, int argc, char **argv,
4331	   char *combinedopt)
4332{
4333	int c;
4334	union ccb *ccb;
4335	int numtags = -1;
4336	int retval = 0;
4337	int quiet = 0;
4338	char pathstr[1024];
4339
4340	ccb = cam_getccb(device);
4341
4342	if (ccb == NULL) {
4343		warnx("tagcontrol: error allocating ccb");
4344		return(1);
4345	}
4346
4347	while ((c = getopt(argc, argv, combinedopt)) != -1) {
4348		switch(c) {
4349		case 'N':
4350			numtags = strtol(optarg, NULL, 0);
4351			if (numtags < 0) {
4352				warnx("tag count %d is < 0", numtags);
4353				retval = 1;
4354				goto tagcontrol_bailout;
4355			}
4356			break;
4357		case 'q':
4358			quiet++;
4359			break;
4360		default:
4361			break;
4362		}
4363	}
4364
4365	cam_path_string(device, pathstr, sizeof(pathstr));
4366
4367	if (numtags >= 0) {
4368		bzero(&(&ccb->ccb_h)[1],
4369		      sizeof(struct ccb_relsim) - sizeof(struct ccb_hdr));
4370		ccb->ccb_h.func_code = XPT_REL_SIMQ;
4371		ccb->ccb_h.flags = CAM_DEV_QFREEZE;
4372		ccb->crs.release_flags = RELSIM_ADJUST_OPENINGS;
4373		ccb->crs.openings = numtags;
4374
4375
4376		if (cam_send_ccb(device, ccb) < 0) {
4377			perror("error sending XPT_REL_SIMQ CCB");
4378			retval = 1;
4379			goto tagcontrol_bailout;
4380		}
4381
4382		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
4383			warnx("XPT_REL_SIMQ CCB failed");
4384			cam_error_print(device, ccb, CAM_ESF_ALL,
4385					CAM_EPF_ALL, stderr);
4386			retval = 1;
4387			goto tagcontrol_bailout;
4388		}
4389
4390
4391		if (quiet == 0)
4392			fprintf(stdout, "%stagged openings now %d\n",
4393				pathstr, ccb->crs.openings);
4394	}
4395
4396	bzero(&(&ccb->ccb_h)[1],
4397	      sizeof(struct ccb_getdevstats) - sizeof(struct ccb_hdr));
4398
4399	ccb->ccb_h.func_code = XPT_GDEV_STATS;
4400
4401	if (cam_send_ccb(device, ccb) < 0) {
4402		perror("error sending XPT_GDEV_STATS CCB");
4403		retval = 1;
4404		goto tagcontrol_bailout;
4405	}
4406
4407	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
4408		warnx("XPT_GDEV_STATS CCB failed");
4409		cam_error_print(device, ccb, CAM_ESF_ALL,
4410				CAM_EPF_ALL, stderr);
4411		retval = 1;
4412		goto tagcontrol_bailout;
4413	}
4414
4415	if (arglist & CAM_ARG_VERBOSE) {
4416		fprintf(stdout, "%s", pathstr);
4417		fprintf(stdout, "dev_openings  %d\n", ccb->cgds.dev_openings);
4418		fprintf(stdout, "%s", pathstr);
4419		fprintf(stdout, "dev_active    %d\n", ccb->cgds.dev_active);
4420		fprintf(stdout, "%s", pathstr);
4421		fprintf(stdout, "devq_openings %d\n", ccb->cgds.devq_openings);
4422		fprintf(stdout, "%s", pathstr);
4423		fprintf(stdout, "devq_queued   %d\n", ccb->cgds.devq_queued);
4424		fprintf(stdout, "%s", pathstr);
4425		fprintf(stdout, "held          %d\n", ccb->cgds.held);
4426		fprintf(stdout, "%s", pathstr);
4427		fprintf(stdout, "mintags       %d\n", ccb->cgds.mintags);
4428		fprintf(stdout, "%s", pathstr);
4429		fprintf(stdout, "maxtags       %d\n", ccb->cgds.maxtags);
4430	} else {
4431		if (quiet == 0) {
4432			fprintf(stdout, "%s", pathstr);
4433			fprintf(stdout, "device openings: ");
4434		}
4435		fprintf(stdout, "%d\n", ccb->cgds.dev_openings +
4436			ccb->cgds.dev_active);
4437	}
4438
4439tagcontrol_bailout:
4440
4441	cam_freeccb(ccb);
4442	return(retval);
4443}
4444
4445static void
4446cts_print(struct cam_device *device, struct ccb_trans_settings *cts)
4447{
4448	char pathstr[1024];
4449
4450	cam_path_string(device, pathstr, sizeof(pathstr));
4451
4452	if (cts->transport == XPORT_SPI) {
4453		struct ccb_trans_settings_spi *spi =
4454		    &cts->xport_specific.spi;
4455
4456		if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) {
4457
4458			fprintf(stdout, "%ssync parameter: %d\n", pathstr,
4459				spi->sync_period);
4460
4461			if (spi->sync_offset != 0) {
4462				u_int freq;
4463
4464				freq = scsi_calc_syncsrate(spi->sync_period);
4465				fprintf(stdout, "%sfrequency: %d.%03dMHz\n",
4466					pathstr, freq / 1000, freq % 1000);
4467			}
4468		}
4469
4470		if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) {
4471			fprintf(stdout, "%soffset: %d\n", pathstr,
4472			    spi->sync_offset);
4473		}
4474
4475		if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) {
4476			fprintf(stdout, "%sbus width: %d bits\n", pathstr,
4477				(0x01 << spi->bus_width) * 8);
4478		}
4479
4480		if (spi->valid & CTS_SPI_VALID_DISC) {
4481			fprintf(stdout, "%sdisconnection is %s\n", pathstr,
4482				(spi->flags & CTS_SPI_FLAGS_DISC_ENB) ?
4483				"enabled" : "disabled");
4484		}
4485	}
4486	if (cts->transport == XPORT_FC) {
4487		struct ccb_trans_settings_fc *fc =
4488		    &cts->xport_specific.fc;
4489
4490		if (fc->valid & CTS_FC_VALID_WWNN)
4491			fprintf(stdout, "%sWWNN: 0x%llx\n", pathstr,
4492			    (long long) fc->wwnn);
4493		if (fc->valid & CTS_FC_VALID_WWPN)
4494			fprintf(stdout, "%sWWPN: 0x%llx\n", pathstr,
4495			    (long long) fc->wwpn);
4496		if (fc->valid & CTS_FC_VALID_PORT)
4497			fprintf(stdout, "%sPortID: 0x%x\n", pathstr, fc->port);
4498		if (fc->valid & CTS_FC_VALID_SPEED)
4499			fprintf(stdout, "%stransfer speed: %d.%03dMB/s\n",
4500			    pathstr, fc->bitrate / 1000, fc->bitrate % 1000);
4501	}
4502	if (cts->transport == XPORT_SAS) {
4503		struct ccb_trans_settings_sas *sas =
4504		    &cts->xport_specific.sas;
4505
4506		if (sas->valid & CTS_SAS_VALID_SPEED)
4507			fprintf(stdout, "%stransfer speed: %d.%03dMB/s\n",
4508			    pathstr, sas->bitrate / 1000, sas->bitrate % 1000);
4509	}
4510	if (cts->transport == XPORT_ATA) {
4511		struct ccb_trans_settings_pata *pata =
4512		    &cts->xport_specific.ata;
4513
4514		if ((pata->valid & CTS_ATA_VALID_MODE) != 0) {
4515			fprintf(stdout, "%sATA mode: %s\n", pathstr,
4516				ata_mode2string(pata->mode));
4517		}
4518		if ((pata->valid & CTS_ATA_VALID_ATAPI) != 0) {
4519			fprintf(stdout, "%sATAPI packet length: %d\n", pathstr,
4520				pata->atapi);
4521		}
4522		if ((pata->valid & CTS_ATA_VALID_BYTECOUNT) != 0) {
4523			fprintf(stdout, "%sPIO transaction length: %d\n",
4524				pathstr, pata->bytecount);
4525		}
4526	}
4527	if (cts->transport == XPORT_SATA) {
4528		struct ccb_trans_settings_sata *sata =
4529		    &cts->xport_specific.sata;
4530
4531		if ((sata->valid & CTS_SATA_VALID_REVISION) != 0) {
4532			fprintf(stdout, "%sSATA revision: %d.x\n", pathstr,
4533				sata->revision);
4534		}
4535		if ((sata->valid & CTS_SATA_VALID_MODE) != 0) {
4536			fprintf(stdout, "%sATA mode: %s\n", pathstr,
4537				ata_mode2string(sata->mode));
4538		}
4539		if ((sata->valid & CTS_SATA_VALID_ATAPI) != 0) {
4540			fprintf(stdout, "%sATAPI packet length: %d\n", pathstr,
4541				sata->atapi);
4542		}
4543		if ((sata->valid & CTS_SATA_VALID_BYTECOUNT) != 0) {
4544			fprintf(stdout, "%sPIO transaction length: %d\n",
4545				pathstr, sata->bytecount);
4546		}
4547		if ((sata->valid & CTS_SATA_VALID_PM) != 0) {
4548			fprintf(stdout, "%sPMP presence: %d\n", pathstr,
4549				sata->pm_present);
4550		}
4551		if ((sata->valid & CTS_SATA_VALID_TAGS) != 0) {
4552			fprintf(stdout, "%sNumber of tags: %d\n", pathstr,
4553				sata->tags);
4554		}
4555		if ((sata->valid & CTS_SATA_VALID_CAPS) != 0) {
4556			fprintf(stdout, "%sSATA capabilities: %08x\n", pathstr,
4557				sata->caps);
4558		}
4559	}
4560	if (cts->protocol == PROTO_ATA) {
4561		struct ccb_trans_settings_ata *ata=
4562		    &cts->proto_specific.ata;
4563
4564		if (ata->valid & CTS_ATA_VALID_TQ) {
4565			fprintf(stdout, "%stagged queueing: %s\n", pathstr,
4566				(ata->flags & CTS_ATA_FLAGS_TAG_ENB) ?
4567				"enabled" : "disabled");
4568		}
4569	}
4570	if (cts->protocol == PROTO_SCSI) {
4571		struct ccb_trans_settings_scsi *scsi=
4572		    &cts->proto_specific.scsi;
4573
4574		if (scsi->valid & CTS_SCSI_VALID_TQ) {
4575			fprintf(stdout, "%stagged queueing: %s\n", pathstr,
4576				(scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) ?
4577				"enabled" : "disabled");
4578		}
4579	}
4580
4581}
4582
4583/*
4584 * Get a path inquiry CCB for the specified device.
4585 */
4586static int
4587get_cpi(struct cam_device *device, struct ccb_pathinq *cpi)
4588{
4589	union ccb *ccb;
4590	int retval = 0;
4591
4592	ccb = cam_getccb(device);
4593	if (ccb == NULL) {
4594		warnx("get_cpi: couldn't allocate CCB");
4595		return(1);
4596	}
4597	bzero(&(&ccb->ccb_h)[1],
4598	      sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr));
4599	ccb->ccb_h.func_code = XPT_PATH_INQ;
4600	if (cam_send_ccb(device, ccb) < 0) {
4601		warn("get_cpi: error sending Path Inquiry CCB");
4602		if (arglist & CAM_ARG_VERBOSE)
4603			cam_error_print(device, ccb, CAM_ESF_ALL,
4604					CAM_EPF_ALL, stderr);
4605		retval = 1;
4606		goto get_cpi_bailout;
4607	}
4608	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
4609		if (arglist & CAM_ARG_VERBOSE)
4610			cam_error_print(device, ccb, CAM_ESF_ALL,
4611					CAM_EPF_ALL, stderr);
4612		retval = 1;
4613		goto get_cpi_bailout;
4614	}
4615	bcopy(&ccb->cpi, cpi, sizeof(struct ccb_pathinq));
4616
4617get_cpi_bailout:
4618	cam_freeccb(ccb);
4619	return(retval);
4620}
4621
4622/*
4623 * Get a get device CCB for the specified device.
4624 */
4625static int
4626get_cgd(struct cam_device *device, struct ccb_getdev *cgd)
4627{
4628	union ccb *ccb;
4629	int retval = 0;
4630
4631	ccb = cam_getccb(device);
4632	if (ccb == NULL) {
4633		warnx("get_cgd: couldn't allocate CCB");
4634		return(1);
4635	}
4636	bzero(&(&ccb->ccb_h)[1],
4637	      sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr));
4638	ccb->ccb_h.func_code = XPT_GDEV_TYPE;
4639	if (cam_send_ccb(device, ccb) < 0) {
4640		warn("get_cgd: error sending Path Inquiry CCB");
4641		if (arglist & CAM_ARG_VERBOSE)
4642			cam_error_print(device, ccb, CAM_ESF_ALL,
4643					CAM_EPF_ALL, stderr);
4644		retval = 1;
4645		goto get_cgd_bailout;
4646	}
4647	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
4648		if (arglist & CAM_ARG_VERBOSE)
4649			cam_error_print(device, ccb, CAM_ESF_ALL,
4650					CAM_EPF_ALL, stderr);
4651		retval = 1;
4652		goto get_cgd_bailout;
4653	}
4654	bcopy(&ccb->cgd, cgd, sizeof(struct ccb_getdev));
4655
4656get_cgd_bailout:
4657	cam_freeccb(ccb);
4658	return(retval);
4659}
4660
4661/* return the type of disk (really the command type) */
4662static const char *
4663get_disk_type(struct cam_device *device)
4664{
4665	struct ccb_getdev	cgd;
4666
4667	(void) memset(&cgd, 0x0, sizeof(cgd));
4668	get_cgd(device, &cgd);
4669	switch(cgd.protocol) {
4670	case PROTO_SCSI:
4671		return "scsi";
4672	case PROTO_ATA:
4673	case PROTO_ATAPI:
4674	case PROTO_SATAPM:
4675		return "ata";
4676	default:
4677		return "unknown";
4678	}
4679}
4680
4681static void
4682cpi_print(struct ccb_pathinq *cpi)
4683{
4684	char adapter_str[1024];
4685	int i;
4686
4687	snprintf(adapter_str, sizeof(adapter_str),
4688		 "%s%d:", cpi->dev_name, cpi->unit_number);
4689
4690	fprintf(stdout, "%s SIM/HBA version: %d\n", adapter_str,
4691		cpi->version_num);
4692
4693	for (i = 1; i < 0xff; i = i << 1) {
4694		const char *str;
4695
4696		if ((i & cpi->hba_inquiry) == 0)
4697			continue;
4698
4699		fprintf(stdout, "%s supports ", adapter_str);
4700
4701		switch(i) {
4702		case PI_MDP_ABLE:
4703			str = "MDP message";
4704			break;
4705		case PI_WIDE_32:
4706			str = "32 bit wide SCSI";
4707			break;
4708		case PI_WIDE_16:
4709			str = "16 bit wide SCSI";
4710			break;
4711		case PI_SDTR_ABLE:
4712			str = "SDTR message";
4713			break;
4714		case PI_LINKED_CDB:
4715			str = "linked CDBs";
4716			break;
4717		case PI_TAG_ABLE:
4718			str = "tag queue messages";
4719			break;
4720		case PI_SOFT_RST:
4721			str = "soft reset alternative";
4722			break;
4723		case PI_SATAPM:
4724			str = "SATA Port Multiplier";
4725			break;
4726		default:
4727			str = "unknown PI bit set";
4728			break;
4729		}
4730		fprintf(stdout, "%s\n", str);
4731	}
4732
4733	for (i = 1; i < 0xff; i = i << 1) {
4734		const char *str;
4735
4736		if ((i & cpi->hba_misc) == 0)
4737			continue;
4738
4739		fprintf(stdout, "%s ", adapter_str);
4740
4741		switch(i) {
4742		case PIM_SCANHILO:
4743			str = "bus scans from high ID to low ID";
4744			break;
4745		case PIM_NOREMOVE:
4746			str = "removable devices not included in scan";
4747			break;
4748		case PIM_NOINITIATOR:
4749			str = "initiator role not supported";
4750			break;
4751		case PIM_NOBUSRESET:
4752			str = "user has disabled initial BUS RESET or"
4753			      " controller is in target/mixed mode";
4754			break;
4755		case PIM_NO_6_BYTE:
4756			str = "do not send 6-byte commands";
4757			break;
4758		case PIM_SEQSCAN:
4759			str = "scan bus sequentially";
4760			break;
4761		default:
4762			str = "unknown PIM bit set";
4763			break;
4764		}
4765		fprintf(stdout, "%s\n", str);
4766	}
4767
4768	for (i = 1; i < 0xff; i = i << 1) {
4769		const char *str;
4770
4771		if ((i & cpi->target_sprt) == 0)
4772			continue;
4773
4774		fprintf(stdout, "%s supports ", adapter_str);
4775		switch(i) {
4776		case PIT_PROCESSOR:
4777			str = "target mode processor mode";
4778			break;
4779		case PIT_PHASE:
4780			str = "target mode phase cog. mode";
4781			break;
4782		case PIT_DISCONNECT:
4783			str = "disconnects in target mode";
4784			break;
4785		case PIT_TERM_IO:
4786			str = "terminate I/O message in target mode";
4787			break;
4788		case PIT_GRP_6:
4789			str = "group 6 commands in target mode";
4790			break;
4791		case PIT_GRP_7:
4792			str = "group 7 commands in target mode";
4793			break;
4794		default:
4795			str = "unknown PIT bit set";
4796			break;
4797		}
4798
4799		fprintf(stdout, "%s\n", str);
4800	}
4801	fprintf(stdout, "%s HBA engine count: %d\n", adapter_str,
4802		cpi->hba_eng_cnt);
4803	fprintf(stdout, "%s maximum target: %d\n", adapter_str,
4804		cpi->max_target);
4805	fprintf(stdout, "%s maximum LUN: %d\n", adapter_str,
4806		cpi->max_lun);
4807	fprintf(stdout, "%s highest path ID in subsystem: %d\n",
4808		adapter_str, cpi->hpath_id);
4809	fprintf(stdout, "%s initiator ID: %d\n", adapter_str,
4810		cpi->initiator_id);
4811	fprintf(stdout, "%s SIM vendor: %s\n", adapter_str, cpi->sim_vid);
4812	fprintf(stdout, "%s HBA vendor: %s\n", adapter_str, cpi->hba_vid);
4813	fprintf(stdout, "%s HBA vendor ID: 0x%04x\n",
4814	    adapter_str, cpi->hba_vendor);
4815	fprintf(stdout, "%s HBA device ID: 0x%04x\n",
4816	    adapter_str, cpi->hba_device);
4817	fprintf(stdout, "%s HBA subvendor ID: 0x%04x\n",
4818	    adapter_str, cpi->hba_subvendor);
4819	fprintf(stdout, "%s HBA subdevice ID: 0x%04x\n",
4820	    adapter_str, cpi->hba_subdevice);
4821	fprintf(stdout, "%s bus ID: %d\n", adapter_str, cpi->bus_id);
4822	fprintf(stdout, "%s base transfer speed: ", adapter_str);
4823	if (cpi->base_transfer_speed > 1000)
4824		fprintf(stdout, "%d.%03dMB/sec\n",
4825			cpi->base_transfer_speed / 1000,
4826			cpi->base_transfer_speed % 1000);
4827	else
4828		fprintf(stdout, "%dKB/sec\n",
4829			(cpi->base_transfer_speed % 1000) * 1000);
4830	fprintf(stdout, "%s maximum transfer size: %u bytes\n",
4831	    adapter_str, cpi->maxio);
4832}
4833
4834static int
4835get_print_cts(struct cam_device *device, int user_settings, int quiet,
4836	      struct ccb_trans_settings *cts)
4837{
4838	int retval;
4839	union ccb *ccb;
4840
4841	retval = 0;
4842	ccb = cam_getccb(device);
4843
4844	if (ccb == NULL) {
4845		warnx("get_print_cts: error allocating ccb");
4846		return(1);
4847	}
4848
4849	bzero(&(&ccb->ccb_h)[1],
4850	      sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr));
4851
4852	ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
4853
4854	if (user_settings == 0)
4855		ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS;
4856	else
4857		ccb->cts.type = CTS_TYPE_USER_SETTINGS;
4858
4859	if (cam_send_ccb(device, ccb) < 0) {
4860		perror("error sending XPT_GET_TRAN_SETTINGS CCB");
4861		if (arglist & CAM_ARG_VERBOSE)
4862			cam_error_print(device, ccb, CAM_ESF_ALL,
4863					CAM_EPF_ALL, stderr);
4864		retval = 1;
4865		goto get_print_cts_bailout;
4866	}
4867
4868	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
4869		warnx("XPT_GET_TRANS_SETTINGS CCB failed");
4870		if (arglist & CAM_ARG_VERBOSE)
4871			cam_error_print(device, ccb, CAM_ESF_ALL,
4872					CAM_EPF_ALL, stderr);
4873		retval = 1;
4874		goto get_print_cts_bailout;
4875	}
4876
4877	if (quiet == 0)
4878		cts_print(device, &ccb->cts);
4879
4880	if (cts != NULL)
4881		bcopy(&ccb->cts, cts, sizeof(struct ccb_trans_settings));
4882
4883get_print_cts_bailout:
4884
4885	cam_freeccb(ccb);
4886
4887	return(retval);
4888}
4889
4890static int
4891ratecontrol(struct cam_device *device, int retry_count, int timeout,
4892	    int argc, char **argv, char *combinedopt)
4893{
4894	int c;
4895	union ccb *ccb;
4896	int user_settings = 0;
4897	int retval = 0;
4898	int disc_enable = -1, tag_enable = -1;
4899	int mode = -1;
4900	int offset = -1;
4901	double syncrate = -1;
4902	int bus_width = -1;
4903	int quiet = 0;
4904	int change_settings = 0, send_tur = 0;
4905	struct ccb_pathinq cpi;
4906
4907	ccb = cam_getccb(device);
4908	if (ccb == NULL) {
4909		warnx("ratecontrol: error allocating ccb");
4910		return(1);
4911	}
4912	while ((c = getopt(argc, argv, combinedopt)) != -1) {
4913		switch(c){
4914		case 'a':
4915			send_tur = 1;
4916			break;
4917		case 'c':
4918			user_settings = 0;
4919			break;
4920		case 'D':
4921			if (strncasecmp(optarg, "enable", 6) == 0)
4922				disc_enable = 1;
4923			else if (strncasecmp(optarg, "disable", 7) == 0)
4924				disc_enable = 0;
4925			else {
4926				warnx("-D argument \"%s\" is unknown", optarg);
4927				retval = 1;
4928				goto ratecontrol_bailout;
4929			}
4930			change_settings = 1;
4931			break;
4932		case 'M':
4933			mode = ata_string2mode(optarg);
4934			if (mode < 0) {
4935				warnx("unknown mode '%s'", optarg);
4936				retval = 1;
4937				goto ratecontrol_bailout;
4938			}
4939			change_settings = 1;
4940			break;
4941		case 'O':
4942			offset = strtol(optarg, NULL, 0);
4943			if (offset < 0) {
4944				warnx("offset value %d is < 0", offset);
4945				retval = 1;
4946				goto ratecontrol_bailout;
4947			}
4948			change_settings = 1;
4949			break;
4950		case 'q':
4951			quiet++;
4952			break;
4953		case 'R':
4954			syncrate = atof(optarg);
4955			if (syncrate < 0) {
4956				warnx("sync rate %f is < 0", syncrate);
4957				retval = 1;
4958				goto ratecontrol_bailout;
4959			}
4960			change_settings = 1;
4961			break;
4962		case 'T':
4963			if (strncasecmp(optarg, "enable", 6) == 0)
4964				tag_enable = 1;
4965			else if (strncasecmp(optarg, "disable", 7) == 0)
4966				tag_enable = 0;
4967			else {
4968				warnx("-T argument \"%s\" is unknown", optarg);
4969				retval = 1;
4970				goto ratecontrol_bailout;
4971			}
4972			change_settings = 1;
4973			break;
4974		case 'U':
4975			user_settings = 1;
4976			break;
4977		case 'W':
4978			bus_width = strtol(optarg, NULL, 0);
4979			if (bus_width < 0) {
4980				warnx("bus width %d is < 0", bus_width);
4981				retval = 1;
4982				goto ratecontrol_bailout;
4983			}
4984			change_settings = 1;
4985			break;
4986		default:
4987			break;
4988		}
4989	}
4990	bzero(&(&ccb->ccb_h)[1],
4991	      sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr));
4992	/*
4993	 * Grab path inquiry information, so we can determine whether
4994	 * or not the initiator is capable of the things that the user
4995	 * requests.
4996	 */
4997	ccb->ccb_h.func_code = XPT_PATH_INQ;
4998	if (cam_send_ccb(device, ccb) < 0) {
4999		perror("error sending XPT_PATH_INQ CCB");
5000		if (arglist & CAM_ARG_VERBOSE) {
5001			cam_error_print(device, ccb, CAM_ESF_ALL,
5002					CAM_EPF_ALL, stderr);
5003		}
5004		retval = 1;
5005		goto ratecontrol_bailout;
5006	}
5007	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
5008		warnx("XPT_PATH_INQ CCB failed");
5009		if (arglist & CAM_ARG_VERBOSE) {
5010			cam_error_print(device, ccb, CAM_ESF_ALL,
5011					CAM_EPF_ALL, stderr);
5012		}
5013		retval = 1;
5014		goto ratecontrol_bailout;
5015	}
5016	bcopy(&ccb->cpi, &cpi, sizeof(struct ccb_pathinq));
5017	bzero(&(&ccb->ccb_h)[1],
5018	      sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr));
5019	if (quiet == 0) {
5020		fprintf(stdout, "%s parameters:\n",
5021		    user_settings ? "User" : "Current");
5022	}
5023	retval = get_print_cts(device, user_settings, quiet, &ccb->cts);
5024	if (retval != 0)
5025		goto ratecontrol_bailout;
5026
5027	if (arglist & CAM_ARG_VERBOSE)
5028		cpi_print(&cpi);
5029
5030	if (change_settings) {
5031		int didsettings = 0;
5032		struct ccb_trans_settings_spi *spi = NULL;
5033		struct ccb_trans_settings_pata *pata = NULL;
5034		struct ccb_trans_settings_sata *sata = NULL;
5035		struct ccb_trans_settings_ata *ata = NULL;
5036		struct ccb_trans_settings_scsi *scsi = NULL;
5037
5038		if (ccb->cts.transport == XPORT_SPI)
5039			spi = &ccb->cts.xport_specific.spi;
5040		if (ccb->cts.transport == XPORT_ATA)
5041			pata = &ccb->cts.xport_specific.ata;
5042		if (ccb->cts.transport == XPORT_SATA)
5043			sata = &ccb->cts.xport_specific.sata;
5044		if (ccb->cts.protocol == PROTO_ATA)
5045			ata = &ccb->cts.proto_specific.ata;
5046		if (ccb->cts.protocol == PROTO_SCSI)
5047			scsi = &ccb->cts.proto_specific.scsi;
5048		ccb->cts.xport_specific.valid = 0;
5049		ccb->cts.proto_specific.valid = 0;
5050		if (spi && disc_enable != -1) {
5051			spi->valid |= CTS_SPI_VALID_DISC;
5052			if (disc_enable == 0)
5053				spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
5054			else
5055				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
5056			didsettings++;
5057		}
5058		if (tag_enable != -1) {
5059			if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0) {
5060				warnx("HBA does not support tagged queueing, "
5061				      "so you cannot modify tag settings");
5062				retval = 1;
5063				goto ratecontrol_bailout;
5064			}
5065			if (ata) {
5066				ata->valid |= CTS_SCSI_VALID_TQ;
5067				if (tag_enable == 0)
5068					ata->flags &= ~CTS_ATA_FLAGS_TAG_ENB;
5069				else
5070					ata->flags |= CTS_ATA_FLAGS_TAG_ENB;
5071				didsettings++;
5072			} else if (scsi) {
5073				scsi->valid |= CTS_SCSI_VALID_TQ;
5074				if (tag_enable == 0)
5075					scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
5076				else
5077					scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
5078				didsettings++;
5079			}
5080		}
5081		if (spi && offset != -1) {
5082			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
5083				warnx("HBA is not capable of changing offset");
5084				retval = 1;
5085				goto ratecontrol_bailout;
5086			}
5087			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
5088			spi->sync_offset = offset;
5089			didsettings++;
5090		}
5091		if (spi && syncrate != -1) {
5092			int prelim_sync_period;
5093
5094			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
5095				warnx("HBA is not capable of changing "
5096				      "transfer rates");
5097				retval = 1;
5098				goto ratecontrol_bailout;
5099			}
5100			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
5101			/*
5102			 * The sync rate the user gives us is in MHz.
5103			 * We need to translate it into KHz for this
5104			 * calculation.
5105			 */
5106			syncrate *= 1000;
5107			/*
5108			 * Next, we calculate a "preliminary" sync period
5109			 * in tenths of a nanosecond.
5110			 */
5111			if (syncrate == 0)
5112				prelim_sync_period = 0;
5113			else
5114				prelim_sync_period = 10000000 / syncrate;
5115			spi->sync_period =
5116				scsi_calc_syncparam(prelim_sync_period);
5117			didsettings++;
5118		}
5119		if (sata && syncrate != -1) {
5120			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
5121				warnx("HBA is not capable of changing "
5122				      "transfer rates");
5123				retval = 1;
5124				goto ratecontrol_bailout;
5125			}
5126			if  (!user_settings) {
5127				warnx("You can modify only user rate "
5128				    "settings for SATA");
5129				retval = 1;
5130				goto ratecontrol_bailout;
5131			}
5132			sata->revision = ata_speed2revision(syncrate * 100);
5133			if (sata->revision < 0) {
5134				warnx("Invalid rate %f", syncrate);
5135				retval = 1;
5136				goto ratecontrol_bailout;
5137			}
5138			sata->valid |= CTS_SATA_VALID_REVISION;
5139			didsettings++;
5140		}
5141		if ((pata || sata) && mode != -1) {
5142			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
5143				warnx("HBA is not capable of changing "
5144				      "transfer rates");
5145				retval = 1;
5146				goto ratecontrol_bailout;
5147			}
5148			if  (!user_settings) {
5149				warnx("You can modify only user mode "
5150				    "settings for ATA/SATA");
5151				retval = 1;
5152				goto ratecontrol_bailout;
5153			}
5154			if (pata) {
5155				pata->mode = mode;
5156				pata->valid |= CTS_ATA_VALID_MODE;
5157			} else {
5158				sata->mode = mode;
5159				sata->valid |= CTS_SATA_VALID_MODE;
5160			}
5161			didsettings++;
5162		}
5163		/*
5164		 * The bus_width argument goes like this:
5165		 * 0 == 8 bit
5166		 * 1 == 16 bit
5167		 * 2 == 32 bit
5168		 * Therefore, if you shift the number of bits given on the
5169		 * command line right by 4, you should get the correct
5170		 * number.
5171		 */
5172		if (spi && bus_width != -1) {
5173			/*
5174			 * We might as well validate things here with a
5175			 * decipherable error message, rather than what
5176			 * will probably be an indecipherable error message
5177			 * by the time it gets back to us.
5178			 */
5179			if ((bus_width == 16)
5180			 && ((cpi.hba_inquiry & PI_WIDE_16) == 0)) {
5181				warnx("HBA does not support 16 bit bus width");
5182				retval = 1;
5183				goto ratecontrol_bailout;
5184			} else if ((bus_width == 32)
5185				&& ((cpi.hba_inquiry & PI_WIDE_32) == 0)) {
5186				warnx("HBA does not support 32 bit bus width");
5187				retval = 1;
5188				goto ratecontrol_bailout;
5189			} else if ((bus_width != 8)
5190				&& (bus_width != 16)
5191				&& (bus_width != 32)) {
5192				warnx("Invalid bus width %d", bus_width);
5193				retval = 1;
5194				goto ratecontrol_bailout;
5195			}
5196			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
5197			spi->bus_width = bus_width >> 4;
5198			didsettings++;
5199		}
5200		if  (didsettings == 0) {
5201			goto ratecontrol_bailout;
5202		}
5203		ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
5204		if (cam_send_ccb(device, ccb) < 0) {
5205			perror("error sending XPT_SET_TRAN_SETTINGS CCB");
5206			if (arglist & CAM_ARG_VERBOSE) {
5207				cam_error_print(device, ccb, CAM_ESF_ALL,
5208						CAM_EPF_ALL, stderr);
5209			}
5210			retval = 1;
5211			goto ratecontrol_bailout;
5212		}
5213		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
5214			warnx("XPT_SET_TRANS_SETTINGS CCB failed");
5215			if (arglist & CAM_ARG_VERBOSE) {
5216				cam_error_print(device, ccb, CAM_ESF_ALL,
5217						CAM_EPF_ALL, stderr);
5218			}
5219			retval = 1;
5220			goto ratecontrol_bailout;
5221		}
5222	}
5223	if (send_tur) {
5224		retval = testunitready(device, retry_count, timeout,
5225				       (arglist & CAM_ARG_VERBOSE) ? 0 : 1);
5226		/*
5227		 * If the TUR didn't succeed, just bail.
5228		 */
5229		if (retval != 0) {
5230			if (quiet == 0)
5231				fprintf(stderr, "Test Unit Ready failed\n");
5232			goto ratecontrol_bailout;
5233		}
5234	}
5235	if ((change_settings || send_tur) && !quiet &&
5236	    (ccb->cts.transport == XPORT_ATA ||
5237	     ccb->cts.transport == XPORT_SATA || send_tur)) {
5238		fprintf(stdout, "New parameters:\n");
5239		retval = get_print_cts(device, user_settings, 0, NULL);
5240	}
5241
5242ratecontrol_bailout:
5243	cam_freeccb(ccb);
5244	return(retval);
5245}
5246
5247static int
5248scsiformat(struct cam_device *device, int argc, char **argv,
5249	   char *combinedopt, int retry_count, int timeout)
5250{
5251	union ccb *ccb;
5252	int c;
5253	int ycount = 0, quiet = 0;
5254	int error = 0, retval = 0;
5255	int use_timeout = 10800 * 1000;
5256	int immediate = 1;
5257	struct format_defect_list_header fh;
5258	u_int8_t *data_ptr = NULL;
5259	u_int32_t dxfer_len = 0;
5260	u_int8_t byte2 = 0;
5261	int num_warnings = 0;
5262	int reportonly = 0;
5263
5264	ccb = cam_getccb(device);
5265
5266	if (ccb == NULL) {
5267		warnx("scsiformat: error allocating ccb");
5268		return(1);
5269	}
5270
5271	bzero(&(&ccb->ccb_h)[1],
5272	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
5273
5274	while ((c = getopt(argc, argv, combinedopt)) != -1) {
5275		switch(c) {
5276		case 'q':
5277			quiet++;
5278			break;
5279		case 'r':
5280			reportonly = 1;
5281			break;
5282		case 'w':
5283			immediate = 0;
5284			break;
5285		case 'y':
5286			ycount++;
5287			break;
5288		}
5289	}
5290
5291	if (reportonly)
5292		goto doreport;
5293
5294	if (quiet == 0) {
5295		fprintf(stdout, "You are about to REMOVE ALL DATA from the "
5296			"following device:\n");
5297
5298		error = scsidoinquiry(device, argc, argv, combinedopt,
5299				      retry_count, timeout);
5300
5301		if (error != 0) {
5302			warnx("scsiformat: error sending inquiry");
5303			goto scsiformat_bailout;
5304		}
5305	}
5306
5307	if (ycount == 0) {
5308		if (!get_confirmation()) {
5309			error = 1;
5310			goto scsiformat_bailout;
5311		}
5312	}
5313
5314	if (timeout != 0)
5315		use_timeout = timeout;
5316
5317	if (quiet == 0) {
5318		fprintf(stdout, "Current format timeout is %d seconds\n",
5319			use_timeout / 1000);
5320	}
5321
5322	/*
5323	 * If the user hasn't disabled questions and didn't specify a
5324	 * timeout on the command line, ask them if they want the current
5325	 * timeout.
5326	 */
5327	if ((ycount == 0)
5328	 && (timeout == 0)) {
5329		char str[1024];
5330		int new_timeout = 0;
5331
5332		fprintf(stdout, "Enter new timeout in seconds or press\n"
5333			"return to keep the current timeout [%d] ",
5334			use_timeout / 1000);
5335
5336		if (fgets(str, sizeof(str), stdin) != NULL) {
5337			if (str[0] != '\0')
5338				new_timeout = atoi(str);
5339		}
5340
5341		if (new_timeout != 0) {
5342			use_timeout = new_timeout * 1000;
5343			fprintf(stdout, "Using new timeout value %d\n",
5344				use_timeout / 1000);
5345		}
5346	}
5347
5348	/*
5349	 * Keep this outside the if block below to silence any unused
5350	 * variable warnings.
5351	 */
5352	bzero(&fh, sizeof(fh));
5353
5354	/*
5355	 * If we're in immediate mode, we've got to include the format
5356	 * header
5357	 */
5358	if (immediate != 0) {
5359		fh.byte2 = FU_DLH_IMMED;
5360		data_ptr = (u_int8_t *)&fh;
5361		dxfer_len = sizeof(fh);
5362		byte2 = FU_FMT_DATA;
5363	} else if (quiet == 0) {
5364		fprintf(stdout, "Formatting...");
5365		fflush(stdout);
5366	}
5367
5368	scsi_format_unit(&ccb->csio,
5369			 /* retries */ retry_count,
5370			 /* cbfcnp */ NULL,
5371			 /* tag_action */ MSG_SIMPLE_Q_TAG,
5372			 /* byte2 */ byte2,
5373			 /* ileave */ 0,
5374			 /* data_ptr */ data_ptr,
5375			 /* dxfer_len */ dxfer_len,
5376			 /* sense_len */ SSD_FULL_SIZE,
5377			 /* timeout */ use_timeout);
5378
5379	/* Disable freezing the device queue */
5380	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
5381
5382	if (arglist & CAM_ARG_ERR_RECOVER)
5383		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
5384
5385	if (((retval = cam_send_ccb(device, ccb)) < 0)
5386	 || ((immediate == 0)
5387	   && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP))) {
5388		const char errstr[] = "error sending format command";
5389
5390		if (retval < 0)
5391			warn(errstr);
5392		else
5393			warnx(errstr);
5394
5395		if (arglist & CAM_ARG_VERBOSE) {
5396			cam_error_print(device, ccb, CAM_ESF_ALL,
5397					CAM_EPF_ALL, stderr);
5398		}
5399		error = 1;
5400		goto scsiformat_bailout;
5401	}
5402
5403	/*
5404	 * If we ran in non-immediate mode, we already checked for errors
5405	 * above and printed out any necessary information.  If we're in
5406	 * immediate mode, we need to loop through and get status
5407	 * information periodically.
5408	 */
5409	if (immediate == 0) {
5410		if (quiet == 0) {
5411			fprintf(stdout, "Format Complete\n");
5412		}
5413		goto scsiformat_bailout;
5414	}
5415
5416doreport:
5417	do {
5418		cam_status status;
5419
5420		bzero(&(&ccb->ccb_h)[1],
5421		      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
5422
5423		/*
5424		 * There's really no need to do error recovery or
5425		 * retries here, since we're just going to sit in a
5426		 * loop and wait for the device to finish formatting.
5427		 */
5428		scsi_test_unit_ready(&ccb->csio,
5429				     /* retries */ 0,
5430				     /* cbfcnp */ NULL,
5431				     /* tag_action */ MSG_SIMPLE_Q_TAG,
5432				     /* sense_len */ SSD_FULL_SIZE,
5433				     /* timeout */ 5000);
5434
5435		/* Disable freezing the device queue */
5436		ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
5437
5438		retval = cam_send_ccb(device, ccb);
5439
5440		/*
5441		 * If we get an error from the ioctl, bail out.  SCSI
5442		 * errors are expected.
5443		 */
5444		if (retval < 0) {
5445			warn("error sending CAMIOCOMMAND ioctl");
5446			if (arglist & CAM_ARG_VERBOSE) {
5447				cam_error_print(device, ccb, CAM_ESF_ALL,
5448						CAM_EPF_ALL, stderr);
5449			}
5450			error = 1;
5451			goto scsiformat_bailout;
5452		}
5453
5454		status = ccb->ccb_h.status & CAM_STATUS_MASK;
5455
5456		if ((status != CAM_REQ_CMP)
5457		 && (status == CAM_SCSI_STATUS_ERROR)
5458		 && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) {
5459			struct scsi_sense_data *sense;
5460			int error_code, sense_key, asc, ascq;
5461
5462			sense = &ccb->csio.sense_data;
5463			scsi_extract_sense_len(sense, ccb->csio.sense_len -
5464			    ccb->csio.sense_resid, &error_code, &sense_key,
5465			    &asc, &ascq, /*show_errors*/ 1);
5466
5467			/*
5468			 * According to the SCSI-2 and SCSI-3 specs, a
5469			 * drive that is in the middle of a format should
5470			 * return NOT READY with an ASC of "logical unit
5471			 * not ready, format in progress".  The sense key
5472			 * specific bytes will then be a progress indicator.
5473			 */
5474			if ((sense_key == SSD_KEY_NOT_READY)
5475			 && (asc == 0x04) && (ascq == 0x04)) {
5476				uint8_t sks[3];
5477
5478				if ((scsi_get_sks(sense, ccb->csio.sense_len -
5479				     ccb->csio.sense_resid, sks) == 0)
5480				 && (quiet == 0)) {
5481					int val;
5482					u_int64_t percentage;
5483
5484					val = scsi_2btoul(&sks[1]);
5485					percentage = 10000 * val;
5486
5487					fprintf(stdout,
5488						"\rFormatting:  %ju.%02u %% "
5489						"(%d/%d) done",
5490						(uintmax_t)(percentage /
5491						(0x10000 * 100)),
5492						(unsigned)((percentage /
5493						0x10000) % 100),
5494						val, 0x10000);
5495					fflush(stdout);
5496				} else if ((quiet == 0)
5497					&& (++num_warnings <= 1)) {
5498					warnx("Unexpected SCSI Sense Key "
5499					      "Specific value returned "
5500					      "during format:");
5501					scsi_sense_print(device, &ccb->csio,
5502							 stderr);
5503					warnx("Unable to print status "
5504					      "information, but format will "
5505					      "proceed.");
5506					warnx("will exit when format is "
5507					      "complete");
5508				}
5509				sleep(1);
5510			} else {
5511				warnx("Unexpected SCSI error during format");
5512				cam_error_print(device, ccb, CAM_ESF_ALL,
5513						CAM_EPF_ALL, stderr);
5514				error = 1;
5515				goto scsiformat_bailout;
5516			}
5517
5518		} else if (status != CAM_REQ_CMP) {
5519			warnx("Unexpected CAM status %#x", status);
5520			if (arglist & CAM_ARG_VERBOSE)
5521				cam_error_print(device, ccb, CAM_ESF_ALL,
5522						CAM_EPF_ALL, stderr);
5523			error = 1;
5524			goto scsiformat_bailout;
5525		}
5526
5527	} while((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP);
5528
5529	if (quiet == 0)
5530		fprintf(stdout, "\nFormat Complete\n");
5531
5532scsiformat_bailout:
5533
5534	cam_freeccb(ccb);
5535
5536	return(error);
5537}
5538
5539static int
5540scsireportluns(struct cam_device *device, int argc, char **argv,
5541	       char *combinedopt, int retry_count, int timeout)
5542{
5543	union ccb *ccb;
5544	int c, countonly, lunsonly;
5545	struct scsi_report_luns_data *lundata;
5546	int alloc_len;
5547	uint8_t report_type;
5548	uint32_t list_len, i, j;
5549	int retval;
5550
5551	retval = 0;
5552	lundata = NULL;
5553	report_type = RPL_REPORT_DEFAULT;
5554	ccb = cam_getccb(device);
5555
5556	if (ccb == NULL) {
5557		warnx("%s: error allocating ccb", __func__);
5558		return (1);
5559	}
5560
5561	bzero(&(&ccb->ccb_h)[1],
5562	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
5563
5564	countonly = 0;
5565	lunsonly = 0;
5566
5567	while ((c = getopt(argc, argv, combinedopt)) != -1) {
5568		switch (c) {
5569		case 'c':
5570			countonly++;
5571			break;
5572		case 'l':
5573			lunsonly++;
5574			break;
5575		case 'r':
5576			if (strcasecmp(optarg, "default") == 0)
5577				report_type = RPL_REPORT_DEFAULT;
5578			else if (strcasecmp(optarg, "wellknown") == 0)
5579				report_type = RPL_REPORT_WELLKNOWN;
5580			else if (strcasecmp(optarg, "all") == 0)
5581				report_type = RPL_REPORT_ALL;
5582			else {
5583				warnx("%s: invalid report type \"%s\"",
5584				      __func__, optarg);
5585				retval = 1;
5586				goto bailout;
5587			}
5588			break;
5589		default:
5590			break;
5591		}
5592	}
5593
5594	if ((countonly != 0)
5595	 && (lunsonly != 0)) {
5596		warnx("%s: you can only specify one of -c or -l", __func__);
5597		retval = 1;
5598		goto bailout;
5599	}
5600	/*
5601	 * According to SPC-4, the allocation length must be at least 16
5602	 * bytes -- enough for the header and one LUN.
5603	 */
5604	alloc_len = sizeof(*lundata) + 8;
5605
5606retry:
5607
5608	lundata = malloc(alloc_len);
5609
5610	if (lundata == NULL) {
5611		warn("%s: error mallocing %d bytes", __func__, alloc_len);
5612		retval = 1;
5613		goto bailout;
5614	}
5615
5616	scsi_report_luns(&ccb->csio,
5617			 /*retries*/ retry_count,
5618			 /*cbfcnp*/ NULL,
5619			 /*tag_action*/ MSG_SIMPLE_Q_TAG,
5620			 /*select_report*/ report_type,
5621			 /*rpl_buf*/ lundata,
5622			 /*alloc_len*/ alloc_len,
5623			 /*sense_len*/ SSD_FULL_SIZE,
5624			 /*timeout*/ timeout ? timeout : 5000);
5625
5626	/* Disable freezing the device queue */
5627	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
5628
5629	if (arglist & CAM_ARG_ERR_RECOVER)
5630		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
5631
5632	if (cam_send_ccb(device, ccb) < 0) {
5633		warn("error sending REPORT LUNS command");
5634
5635		if (arglist & CAM_ARG_VERBOSE)
5636			cam_error_print(device, ccb, CAM_ESF_ALL,
5637					CAM_EPF_ALL, stderr);
5638
5639		retval = 1;
5640		goto bailout;
5641	}
5642
5643	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
5644		cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
5645		retval = 1;
5646		goto bailout;
5647	}
5648
5649
5650	list_len = scsi_4btoul(lundata->length);
5651
5652	/*
5653	 * If we need to list the LUNs, and our allocation
5654	 * length was too short, reallocate and retry.
5655	 */
5656	if ((countonly == 0)
5657	 && (list_len > (alloc_len - sizeof(*lundata)))) {
5658		alloc_len = list_len + sizeof(*lundata);
5659		free(lundata);
5660		goto retry;
5661	}
5662
5663	if (lunsonly == 0)
5664		fprintf(stdout, "%u LUN%s found\n", list_len / 8,
5665			((list_len / 8) > 1) ? "s" : "");
5666
5667	if (countonly != 0)
5668		goto bailout;
5669
5670	for (i = 0; i < (list_len / 8); i++) {
5671		int no_more;
5672
5673		no_more = 0;
5674		for (j = 0; j < sizeof(lundata->luns[i].lundata); j += 2) {
5675			if (j != 0)
5676				fprintf(stdout, ",");
5677			switch (lundata->luns[i].lundata[j] &
5678				RPL_LUNDATA_ATYP_MASK) {
5679			case RPL_LUNDATA_ATYP_PERIPH:
5680				if ((lundata->luns[i].lundata[j] &
5681				    RPL_LUNDATA_PERIPH_BUS_MASK) != 0)
5682					fprintf(stdout, "%d:",
5683						lundata->luns[i].lundata[j] &
5684						RPL_LUNDATA_PERIPH_BUS_MASK);
5685				else if ((j == 0)
5686				      && ((lundata->luns[i].lundata[j+2] &
5687					  RPL_LUNDATA_PERIPH_BUS_MASK) == 0))
5688					no_more = 1;
5689
5690				fprintf(stdout, "%d",
5691					lundata->luns[i].lundata[j+1]);
5692				break;
5693			case RPL_LUNDATA_ATYP_FLAT: {
5694				uint8_t tmplun[2];
5695				tmplun[0] = lundata->luns[i].lundata[j] &
5696					RPL_LUNDATA_FLAT_LUN_MASK;
5697				tmplun[1] = lundata->luns[i].lundata[j+1];
5698
5699				fprintf(stdout, "%d", scsi_2btoul(tmplun));
5700				no_more = 1;
5701				break;
5702			}
5703			case RPL_LUNDATA_ATYP_LUN:
5704				fprintf(stdout, "%d:%d:%d",
5705					(lundata->luns[i].lundata[j+1] &
5706					RPL_LUNDATA_LUN_BUS_MASK) >> 5,
5707					lundata->luns[i].lundata[j] &
5708					RPL_LUNDATA_LUN_TARG_MASK,
5709					lundata->luns[i].lundata[j+1] &
5710					RPL_LUNDATA_LUN_LUN_MASK);
5711				break;
5712			case RPL_LUNDATA_ATYP_EXTLUN: {
5713				int field_len_code, eam_code;
5714
5715				eam_code = lundata->luns[i].lundata[j] &
5716					RPL_LUNDATA_EXT_EAM_MASK;
5717				field_len_code = (lundata->luns[i].lundata[j] &
5718					RPL_LUNDATA_EXT_LEN_MASK) >> 4;
5719
5720				if ((eam_code == RPL_LUNDATA_EXT_EAM_WK)
5721				 && (field_len_code == 0x00)) {
5722					fprintf(stdout, "%d",
5723						lundata->luns[i].lundata[j+1]);
5724				} else if ((eam_code ==
5725					    RPL_LUNDATA_EXT_EAM_NOT_SPEC)
5726					&& (field_len_code == 0x03)) {
5727					uint8_t tmp_lun[8];
5728
5729					/*
5730					 * This format takes up all 8 bytes.
5731					 * If we aren't starting at offset 0,
5732					 * that's a bug.
5733					 */
5734					if (j != 0) {
5735						fprintf(stdout, "Invalid "
5736							"offset %d for "
5737							"Extended LUN not "
5738							"specified format", j);
5739						no_more = 1;
5740						break;
5741					}
5742					bzero(tmp_lun, sizeof(tmp_lun));
5743					bcopy(&lundata->luns[i].lundata[j+1],
5744					      &tmp_lun[1], sizeof(tmp_lun) - 1);
5745					fprintf(stdout, "%#jx",
5746					       (intmax_t)scsi_8btou64(tmp_lun));
5747					no_more = 1;
5748				} else {
5749					fprintf(stderr, "Unknown Extended LUN"
5750						"Address method %#x, length "
5751						"code %#x", eam_code,
5752						field_len_code);
5753					no_more = 1;
5754				}
5755				break;
5756			}
5757			default:
5758				fprintf(stderr, "Unknown LUN address method "
5759					"%#x\n", lundata->luns[i].lundata[0] &
5760					RPL_LUNDATA_ATYP_MASK);
5761				break;
5762			}
5763			/*
5764			 * For the flat addressing method, there are no
5765			 * other levels after it.
5766			 */
5767			if (no_more != 0)
5768				break;
5769		}
5770		fprintf(stdout, "\n");
5771	}
5772
5773bailout:
5774
5775	cam_freeccb(ccb);
5776
5777	free(lundata);
5778
5779	return (retval);
5780}
5781
5782static int
5783scsireadcapacity(struct cam_device *device, int argc, char **argv,
5784		 char *combinedopt, int retry_count, int timeout)
5785{
5786	union ccb *ccb;
5787	int blocksizeonly, humanize, numblocks, quiet, sizeonly, baseten;
5788	struct scsi_read_capacity_data rcap;
5789	struct scsi_read_capacity_data_long rcaplong;
5790	uint64_t maxsector;
5791	uint32_t block_len;
5792	int retval;
5793	int c;
5794
5795	blocksizeonly = 0;
5796	humanize = 0;
5797	numblocks = 0;
5798	quiet = 0;
5799	sizeonly = 0;
5800	baseten = 0;
5801	retval = 0;
5802
5803	ccb = cam_getccb(device);
5804
5805	if (ccb == NULL) {
5806		warnx("%s: error allocating ccb", __func__);
5807		return (1);
5808	}
5809
5810	bzero(&(&ccb->ccb_h)[1],
5811	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
5812
5813	while ((c = getopt(argc, argv, combinedopt)) != -1) {
5814		switch (c) {
5815		case 'b':
5816			blocksizeonly++;
5817			break;
5818		case 'h':
5819			humanize++;
5820			baseten = 0;
5821			break;
5822		case 'H':
5823			humanize++;
5824			baseten++;
5825			break;
5826		case 'N':
5827			numblocks++;
5828			break;
5829		case 'q':
5830			quiet++;
5831			break;
5832		case 's':
5833			sizeonly++;
5834			break;
5835		default:
5836			break;
5837		}
5838	}
5839
5840	if ((blocksizeonly != 0)
5841	 && (numblocks != 0)) {
5842		warnx("%s: you can only specify one of -b or -N", __func__);
5843		retval = 1;
5844		goto bailout;
5845	}
5846
5847	if ((blocksizeonly != 0)
5848	 && (sizeonly != 0)) {
5849		warnx("%s: you can only specify one of -b or -s", __func__);
5850		retval = 1;
5851		goto bailout;
5852	}
5853
5854	if ((humanize != 0)
5855	 && (quiet != 0)) {
5856		warnx("%s: you can only specify one of -h/-H or -q", __func__);
5857		retval = 1;
5858		goto bailout;
5859	}
5860
5861	if ((humanize != 0)
5862	 && (blocksizeonly != 0)) {
5863		warnx("%s: you can only specify one of -h/-H or -b", __func__);
5864		retval = 1;
5865		goto bailout;
5866	}
5867
5868	scsi_read_capacity(&ccb->csio,
5869			   /*retries*/ retry_count,
5870			   /*cbfcnp*/ NULL,
5871			   /*tag_action*/ MSG_SIMPLE_Q_TAG,
5872			   &rcap,
5873			   SSD_FULL_SIZE,
5874			   /*timeout*/ timeout ? timeout : 5000);
5875
5876	/* Disable freezing the device queue */
5877	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
5878
5879	if (arglist & CAM_ARG_ERR_RECOVER)
5880		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
5881
5882	if (cam_send_ccb(device, ccb) < 0) {
5883		warn("error sending READ CAPACITY command");
5884
5885		if (arglist & CAM_ARG_VERBOSE)
5886			cam_error_print(device, ccb, CAM_ESF_ALL,
5887					CAM_EPF_ALL, stderr);
5888
5889		retval = 1;
5890		goto bailout;
5891	}
5892
5893	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
5894		cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
5895		retval = 1;
5896		goto bailout;
5897	}
5898
5899	maxsector = scsi_4btoul(rcap.addr);
5900	block_len = scsi_4btoul(rcap.length);
5901
5902	/*
5903	 * A last block of 2^32-1 means that the true capacity is over 2TB,
5904	 * and we need to issue the long READ CAPACITY to get the real
5905	 * capacity.  Otherwise, we're all set.
5906	 */
5907	if (maxsector != 0xffffffff)
5908		goto do_print;
5909
5910	scsi_read_capacity_16(&ccb->csio,
5911			      /*retries*/ retry_count,
5912			      /*cbfcnp*/ NULL,
5913			      /*tag_action*/ MSG_SIMPLE_Q_TAG,
5914			      /*lba*/ 0,
5915			      /*reladdr*/ 0,
5916			      /*pmi*/ 0,
5917			      /*rcap_buf*/ (uint8_t *)&rcaplong,
5918			      /*rcap_buf_len*/ sizeof(rcaplong),
5919			      /*sense_len*/ SSD_FULL_SIZE,
5920			      /*timeout*/ timeout ? timeout : 5000);
5921
5922	/* Disable freezing the device queue */
5923	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
5924
5925	if (arglist & CAM_ARG_ERR_RECOVER)
5926		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
5927
5928	if (cam_send_ccb(device, ccb) < 0) {
5929		warn("error sending READ CAPACITY (16) command");
5930
5931		if (arglist & CAM_ARG_VERBOSE)
5932			cam_error_print(device, ccb, CAM_ESF_ALL,
5933					CAM_EPF_ALL, stderr);
5934
5935		retval = 1;
5936		goto bailout;
5937	}
5938
5939	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
5940		cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
5941		retval = 1;
5942		goto bailout;
5943	}
5944
5945	maxsector = scsi_8btou64(rcaplong.addr);
5946	block_len = scsi_4btoul(rcaplong.length);
5947
5948do_print:
5949	if (blocksizeonly == 0) {
5950		/*
5951		 * Humanize implies !quiet, and also implies numblocks.
5952		 */
5953		if (humanize != 0) {
5954			char tmpstr[6];
5955			int64_t tmpbytes;
5956			int ret;
5957
5958			tmpbytes = (maxsector + 1) * block_len;
5959			ret = humanize_number(tmpstr, sizeof(tmpstr),
5960					      tmpbytes, "", HN_AUTOSCALE,
5961					      HN_B | HN_DECIMAL |
5962					      ((baseten != 0) ?
5963					      HN_DIVISOR_1000 : 0));
5964			if (ret == -1) {
5965				warnx("%s: humanize_number failed!", __func__);
5966				retval = 1;
5967				goto bailout;
5968			}
5969			fprintf(stdout, "Device Size: %s%s", tmpstr,
5970				(sizeonly == 0) ?  ", " : "\n");
5971		} else if (numblocks != 0) {
5972			fprintf(stdout, "%s%ju%s", (quiet == 0) ?
5973				"Blocks: " : "", (uintmax_t)maxsector + 1,
5974				(sizeonly == 0) ? ", " : "\n");
5975		} else {
5976			fprintf(stdout, "%s%ju%s", (quiet == 0) ?
5977				"Last Block: " : "", (uintmax_t)maxsector,
5978				(sizeonly == 0) ? ", " : "\n");
5979		}
5980	}
5981	if (sizeonly == 0)
5982		fprintf(stdout, "%s%u%s\n", (quiet == 0) ?
5983			"Block Length: " : "", block_len, (quiet == 0) ?
5984			" bytes" : "");
5985bailout:
5986	cam_freeccb(ccb);
5987
5988	return (retval);
5989}
5990
5991static int
5992smpcmd(struct cam_device *device, int argc, char **argv, char *combinedopt,
5993       int retry_count, int timeout)
5994{
5995	int c, error = 0;
5996	union ccb *ccb;
5997	uint8_t *smp_request = NULL, *smp_response = NULL;
5998	int request_size = 0, response_size = 0;
5999	int fd_request = 0, fd_response = 0;
6000	char *datastr = NULL;
6001	struct get_hook hook;
6002	int retval;
6003	int flags = 0;
6004
6005	/*
6006	 * Note that at the moment we don't support sending SMP CCBs to
6007	 * devices that aren't probed by CAM.
6008	 */
6009	ccb = cam_getccb(device);
6010	if (ccb == NULL) {
6011		warnx("%s: error allocating CCB", __func__);
6012		return (1);
6013	}
6014
6015	bzero(&(&ccb->ccb_h)[1],
6016	      sizeof(union ccb) - sizeof(struct ccb_hdr));
6017
6018	while ((c = getopt(argc, argv, combinedopt)) != -1) {
6019		switch (c) {
6020		case 'R':
6021			arglist |= CAM_ARG_CMD_IN;
6022			response_size = strtol(optarg, NULL, 0);
6023			if (response_size <= 0) {
6024				warnx("invalid number of response bytes %d",
6025				      response_size);
6026				error = 1;
6027				goto smpcmd_bailout;
6028			}
6029			hook.argc = argc - optind;
6030			hook.argv = argv + optind;
6031			hook.got = 0;
6032			optind++;
6033			datastr = cget(&hook, NULL);
6034			/*
6035			 * If the user supplied "-" instead of a format, he
6036			 * wants the data to be written to stdout.
6037			 */
6038			if ((datastr != NULL)
6039			 && (datastr[0] == '-'))
6040				fd_response = 1;
6041
6042			smp_response = (u_int8_t *)malloc(response_size);
6043			if (smp_response == NULL) {
6044				warn("can't malloc memory for SMP response");
6045				error = 1;
6046				goto smpcmd_bailout;
6047			}
6048			break;
6049		case 'r':
6050			arglist |= CAM_ARG_CMD_OUT;
6051			request_size = strtol(optarg, NULL, 0);
6052			if (request_size <= 0) {
6053				warnx("invalid number of request bytes %d",
6054				      request_size);
6055				error = 1;
6056				goto smpcmd_bailout;
6057			}
6058			hook.argc = argc - optind;
6059			hook.argv = argv + optind;
6060			hook.got = 0;
6061			datastr = cget(&hook, NULL);
6062			smp_request = (u_int8_t *)malloc(request_size);
6063			if (smp_request == NULL) {
6064				warn("can't malloc memory for SMP request");
6065				error = 1;
6066				goto smpcmd_bailout;
6067			}
6068			bzero(smp_request, request_size);
6069			/*
6070			 * If the user supplied "-" instead of a format, he
6071			 * wants the data to be read from stdin.
6072			 */
6073			if ((datastr != NULL)
6074			 && (datastr[0] == '-'))
6075				fd_request = 1;
6076			else
6077				buff_encode_visit(smp_request, request_size,
6078						  datastr,
6079						  iget, &hook);
6080			optind += hook.got;
6081			break;
6082		default:
6083			break;
6084		}
6085	}
6086
6087	/*
6088	 * If fd_data is set, and we're writing to the device, we need to
6089	 * read the data the user wants written from stdin.
6090	 */
6091	if ((fd_request == 1) && (arglist & CAM_ARG_CMD_OUT)) {
6092		ssize_t amt_read;
6093		int amt_to_read = request_size;
6094		u_int8_t *buf_ptr = smp_request;
6095
6096		for (amt_read = 0; amt_to_read > 0;
6097		     amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) {
6098			if (amt_read == -1) {
6099				warn("error reading data from stdin");
6100				error = 1;
6101				goto smpcmd_bailout;
6102			}
6103			amt_to_read -= amt_read;
6104			buf_ptr += amt_read;
6105		}
6106	}
6107
6108	if (((arglist & CAM_ARG_CMD_IN) == 0)
6109	 || ((arglist & CAM_ARG_CMD_OUT) == 0)) {
6110		warnx("%s: need both the request (-r) and response (-R) "
6111		      "arguments", __func__);
6112		error = 1;
6113		goto smpcmd_bailout;
6114	}
6115
6116	flags |= CAM_DEV_QFRZDIS;
6117
6118	cam_fill_smpio(&ccb->smpio,
6119		       /*retries*/ retry_count,
6120		       /*cbfcnp*/ NULL,
6121		       /*flags*/ flags,
6122		       /*smp_request*/ smp_request,
6123		       /*smp_request_len*/ request_size,
6124		       /*smp_response*/ smp_response,
6125		       /*smp_response_len*/ response_size,
6126		       /*timeout*/ timeout ? timeout : 5000);
6127
6128	ccb->smpio.flags = SMP_FLAG_NONE;
6129
6130	if (((retval = cam_send_ccb(device, ccb)) < 0)
6131	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
6132		const char warnstr[] = "error sending command";
6133
6134		if (retval < 0)
6135			warn(warnstr);
6136		else
6137			warnx(warnstr);
6138
6139		if (arglist & CAM_ARG_VERBOSE) {
6140			cam_error_print(device, ccb, CAM_ESF_ALL,
6141					CAM_EPF_ALL, stderr);
6142		}
6143	}
6144
6145	if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
6146	 && (response_size > 0)) {
6147		if (fd_response == 0) {
6148			buff_decode_visit(smp_response, response_size,
6149					  datastr, arg_put, NULL);
6150			fprintf(stdout, "\n");
6151		} else {
6152			ssize_t amt_written;
6153			int amt_to_write = response_size;
6154			u_int8_t *buf_ptr = smp_response;
6155
6156			for (amt_written = 0; (amt_to_write > 0) &&
6157			     (amt_written = write(STDOUT_FILENO, buf_ptr,
6158						  amt_to_write)) > 0;){
6159				amt_to_write -= amt_written;
6160				buf_ptr += amt_written;
6161			}
6162			if (amt_written == -1) {
6163				warn("error writing data to stdout");
6164				error = 1;
6165				goto smpcmd_bailout;
6166			} else if ((amt_written == 0)
6167				&& (amt_to_write > 0)) {
6168				warnx("only wrote %u bytes out of %u",
6169				      response_size - amt_to_write,
6170				      response_size);
6171			}
6172		}
6173	}
6174smpcmd_bailout:
6175	if (ccb != NULL)
6176		cam_freeccb(ccb);
6177
6178	if (smp_request != NULL)
6179		free(smp_request);
6180
6181	if (smp_response != NULL)
6182		free(smp_response);
6183
6184	return (error);
6185}
6186
6187static int
6188smpreportgeneral(struct cam_device *device, int argc, char **argv,
6189		 char *combinedopt, int retry_count, int timeout)
6190{
6191	union ccb *ccb;
6192	struct smp_report_general_request *request = NULL;
6193	struct smp_report_general_response *response = NULL;
6194	struct sbuf *sb = NULL;
6195	int error = 0;
6196	int c, long_response = 0;
6197	int retval;
6198
6199	/*
6200	 * Note that at the moment we don't support sending SMP CCBs to
6201	 * devices that aren't probed by CAM.
6202	 */
6203	ccb = cam_getccb(device);
6204	if (ccb == NULL) {
6205		warnx("%s: error allocating CCB", __func__);
6206		return (1);
6207	}
6208
6209	bzero(&(&ccb->ccb_h)[1],
6210	      sizeof(union ccb) - sizeof(struct ccb_hdr));
6211
6212	while ((c = getopt(argc, argv, combinedopt)) != -1) {
6213		switch (c) {
6214		case 'l':
6215			long_response = 1;
6216			break;
6217		default:
6218			break;
6219		}
6220	}
6221	request = malloc(sizeof(*request));
6222	if (request == NULL) {
6223		warn("%s: unable to allocate %zd bytes", __func__,
6224		     sizeof(*request));
6225		error = 1;
6226		goto bailout;
6227	}
6228
6229	response = malloc(sizeof(*response));
6230	if (response == NULL) {
6231		warn("%s: unable to allocate %zd bytes", __func__,
6232		     sizeof(*response));
6233		error = 1;
6234		goto bailout;
6235	}
6236
6237try_long:
6238	smp_report_general(&ccb->smpio,
6239			   retry_count,
6240			   /*cbfcnp*/ NULL,
6241			   request,
6242			   /*request_len*/ sizeof(*request),
6243			   (uint8_t *)response,
6244			   /*response_len*/ sizeof(*response),
6245			   /*long_response*/ long_response,
6246			   timeout);
6247
6248	if (((retval = cam_send_ccb(device, ccb)) < 0)
6249	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
6250		const char warnstr[] = "error sending command";
6251
6252		if (retval < 0)
6253			warn(warnstr);
6254		else
6255			warnx(warnstr);
6256
6257		if (arglist & CAM_ARG_VERBOSE) {
6258			cam_error_print(device, ccb, CAM_ESF_ALL,
6259					CAM_EPF_ALL, stderr);
6260		}
6261		error = 1;
6262		goto bailout;
6263	}
6264
6265	/*
6266	 * If the device supports the long response bit, try again and see
6267	 * if we can get all of the data.
6268	 */
6269	if ((response->long_response & SMP_RG_LONG_RESPONSE)
6270	 && (long_response == 0)) {
6271		ccb->ccb_h.status = CAM_REQ_INPROG;
6272		bzero(&(&ccb->ccb_h)[1],
6273		      sizeof(union ccb) - sizeof(struct ccb_hdr));
6274		long_response = 1;
6275		goto try_long;
6276	}
6277
6278	/*
6279	 * XXX KDM detect and decode SMP errors here.
6280	 */
6281	sb = sbuf_new_auto();
6282	if (sb == NULL) {
6283		warnx("%s: error allocating sbuf", __func__);
6284		goto bailout;
6285	}
6286
6287	smp_report_general_sbuf(response, sizeof(*response), sb);
6288
6289	if (sbuf_finish(sb) != 0) {
6290		warnx("%s: sbuf_finish", __func__);
6291		goto bailout;
6292	}
6293
6294	printf("%s", sbuf_data(sb));
6295
6296bailout:
6297	if (ccb != NULL)
6298		cam_freeccb(ccb);
6299
6300	if (request != NULL)
6301		free(request);
6302
6303	if (response != NULL)
6304		free(response);
6305
6306	if (sb != NULL)
6307		sbuf_delete(sb);
6308
6309	return (error);
6310}
6311
6312static struct camcontrol_opts phy_ops[] = {
6313	{"nop", SMP_PC_PHY_OP_NOP, CAM_ARG_NONE, NULL},
6314	{"linkreset", SMP_PC_PHY_OP_LINK_RESET, CAM_ARG_NONE, NULL},
6315	{"hardreset", SMP_PC_PHY_OP_HARD_RESET, CAM_ARG_NONE, NULL},
6316	{"disable", SMP_PC_PHY_OP_DISABLE, CAM_ARG_NONE, NULL},
6317	{"clearerrlog", SMP_PC_PHY_OP_CLEAR_ERR_LOG, CAM_ARG_NONE, NULL},
6318	{"clearaffiliation", SMP_PC_PHY_OP_CLEAR_AFFILIATON, CAM_ARG_NONE,NULL},
6319	{"sataportsel", SMP_PC_PHY_OP_TRANS_SATA_PSS, CAM_ARG_NONE, NULL},
6320	{"clearitnl", SMP_PC_PHY_OP_CLEAR_STP_ITN_LS, CAM_ARG_NONE, NULL},
6321	{"setdevname", SMP_PC_PHY_OP_SET_ATT_DEV_NAME, CAM_ARG_NONE, NULL},
6322	{NULL, 0, 0, NULL}
6323};
6324
6325static int
6326smpphycontrol(struct cam_device *device, int argc, char **argv,
6327	      char *combinedopt, int retry_count, int timeout)
6328{
6329	union ccb *ccb;
6330	struct smp_phy_control_request *request = NULL;
6331	struct smp_phy_control_response *response = NULL;
6332	int long_response = 0;
6333	int retval = 0;
6334	int phy = -1;
6335	uint32_t phy_operation = SMP_PC_PHY_OP_NOP;
6336	int phy_op_set = 0;
6337	uint64_t attached_dev_name = 0;
6338	int dev_name_set = 0;
6339	uint32_t min_plr = 0, max_plr = 0;
6340	uint32_t pp_timeout_val = 0;
6341	int slumber_partial = 0;
6342	int set_pp_timeout_val = 0;
6343	int c;
6344
6345	/*
6346	 * Note that at the moment we don't support sending SMP CCBs to
6347	 * devices that aren't probed by CAM.
6348	 */
6349	ccb = cam_getccb(device);
6350	if (ccb == NULL) {
6351		warnx("%s: error allocating CCB", __func__);
6352		return (1);
6353	}
6354
6355	bzero(&(&ccb->ccb_h)[1],
6356	      sizeof(union ccb) - sizeof(struct ccb_hdr));
6357
6358	while ((c = getopt(argc, argv, combinedopt)) != -1) {
6359		switch (c) {
6360		case 'a':
6361		case 'A':
6362		case 's':
6363		case 'S': {
6364			int enable = -1;
6365
6366			if (strcasecmp(optarg, "enable") == 0)
6367				enable = 1;
6368			else if (strcasecmp(optarg, "disable") == 0)
6369				enable = 2;
6370			else {
6371				warnx("%s: Invalid argument %s", __func__,
6372				      optarg);
6373				retval = 1;
6374				goto bailout;
6375			}
6376			switch (c) {
6377			case 's':
6378				slumber_partial |= enable <<
6379						   SMP_PC_SAS_SLUMBER_SHIFT;
6380				break;
6381			case 'S':
6382				slumber_partial |= enable <<
6383						   SMP_PC_SAS_PARTIAL_SHIFT;
6384				break;
6385			case 'a':
6386				slumber_partial |= enable <<
6387						   SMP_PC_SATA_SLUMBER_SHIFT;
6388				break;
6389			case 'A':
6390				slumber_partial |= enable <<
6391						   SMP_PC_SATA_PARTIAL_SHIFT;
6392				break;
6393			default:
6394				warnx("%s: programmer error", __func__);
6395				retval = 1;
6396				goto bailout;
6397				break; /*NOTREACHED*/
6398			}
6399			break;
6400		}
6401		case 'd':
6402			attached_dev_name = (uintmax_t)strtoumax(optarg,
6403								 NULL,0);
6404			dev_name_set = 1;
6405			break;
6406		case 'l':
6407			long_response = 1;
6408			break;
6409		case 'm':
6410			/*
6411			 * We don't do extensive checking here, so this
6412			 * will continue to work when new speeds come out.
6413			 */
6414			min_plr = strtoul(optarg, NULL, 0);
6415			if ((min_plr == 0)
6416			 || (min_plr > 0xf)) {
6417				warnx("%s: invalid link rate %x",
6418				      __func__, min_plr);
6419				retval = 1;
6420				goto bailout;
6421			}
6422			break;
6423		case 'M':
6424			/*
6425			 * We don't do extensive checking here, so this
6426			 * will continue to work when new speeds come out.
6427			 */
6428			max_plr = strtoul(optarg, NULL, 0);
6429			if ((max_plr == 0)
6430			 || (max_plr > 0xf)) {
6431				warnx("%s: invalid link rate %x",
6432				      __func__, max_plr);
6433				retval = 1;
6434				goto bailout;
6435			}
6436			break;
6437		case 'o': {
6438			camcontrol_optret optreturn;
6439			cam_argmask argnums;
6440			const char *subopt;
6441
6442			if (phy_op_set != 0) {
6443				warnx("%s: only one phy operation argument "
6444				      "(-o) allowed", __func__);
6445				retval = 1;
6446				goto bailout;
6447			}
6448
6449			phy_op_set = 1;
6450
6451			/*
6452			 * Allow the user to specify the phy operation
6453			 * numerically, as well as with a name.  This will
6454			 * future-proof it a bit, so options that are added
6455			 * in future specs can be used.
6456			 */
6457			if (isdigit(optarg[0])) {
6458				phy_operation = strtoul(optarg, NULL, 0);
6459				if ((phy_operation == 0)
6460				 || (phy_operation > 0xff)) {
6461					warnx("%s: invalid phy operation %#x",
6462					      __func__, phy_operation);
6463					retval = 1;
6464					goto bailout;
6465				}
6466				break;
6467			}
6468			optreturn = getoption(phy_ops, optarg, &phy_operation,
6469					      &argnums, &subopt);
6470
6471			if (optreturn == CC_OR_AMBIGUOUS) {
6472				warnx("%s: ambiguous option %s", __func__,
6473				      optarg);
6474				usage(0);
6475				retval = 1;
6476				goto bailout;
6477			} else if (optreturn == CC_OR_NOT_FOUND) {
6478				warnx("%s: option %s not found", __func__,
6479				      optarg);
6480				usage(0);
6481				retval = 1;
6482				goto bailout;
6483			}
6484			break;
6485		}
6486		case 'p':
6487			phy = atoi(optarg);
6488			break;
6489		case 'T':
6490			pp_timeout_val = strtoul(optarg, NULL, 0);
6491			if (pp_timeout_val > 15) {
6492				warnx("%s: invalid partial pathway timeout "
6493				      "value %u, need a value less than 16",
6494				      __func__, pp_timeout_val);
6495				retval = 1;
6496				goto bailout;
6497			}
6498			set_pp_timeout_val = 1;
6499			break;
6500		default:
6501			break;
6502		}
6503	}
6504
6505	if (phy == -1) {
6506		warnx("%s: a PHY (-p phy) argument is required",__func__);
6507		retval = 1;
6508		goto bailout;
6509	}
6510
6511	if (((dev_name_set != 0)
6512	  && (phy_operation != SMP_PC_PHY_OP_SET_ATT_DEV_NAME))
6513	 || ((phy_operation == SMP_PC_PHY_OP_SET_ATT_DEV_NAME)
6514	  && (dev_name_set == 0))) {
6515		warnx("%s: -d name and -o setdevname arguments both "
6516		      "required to set device name", __func__);
6517		retval = 1;
6518		goto bailout;
6519	}
6520
6521	request = malloc(sizeof(*request));
6522	if (request == NULL) {
6523		warn("%s: unable to allocate %zd bytes", __func__,
6524		     sizeof(*request));
6525		retval = 1;
6526		goto bailout;
6527	}
6528
6529	response = malloc(sizeof(*response));
6530	if (response == NULL) {
6531		warn("%s: unable to allocate %zd bytes", __func__,
6532		     sizeof(*request));
6533		retval = 1;
6534		goto bailout;
6535	}
6536
6537	smp_phy_control(&ccb->smpio,
6538			retry_count,
6539			/*cbfcnp*/ NULL,
6540			request,
6541			sizeof(*request),
6542			(uint8_t *)response,
6543			sizeof(*response),
6544			long_response,
6545			/*expected_exp_change_count*/ 0,
6546			phy,
6547			phy_operation,
6548			(set_pp_timeout_val != 0) ? 1 : 0,
6549			attached_dev_name,
6550			min_plr,
6551			max_plr,
6552			slumber_partial,
6553			pp_timeout_val,
6554			timeout);
6555
6556	if (((retval = cam_send_ccb(device, ccb)) < 0)
6557	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
6558		const char warnstr[] = "error sending command";
6559
6560		if (retval < 0)
6561			warn(warnstr);
6562		else
6563			warnx(warnstr);
6564
6565		if (arglist & CAM_ARG_VERBOSE) {
6566			/*
6567			 * Use CAM_EPF_NORMAL so we only get one line of
6568			 * SMP command decoding.
6569			 */
6570			cam_error_print(device, ccb, CAM_ESF_ALL,
6571					CAM_EPF_NORMAL, stderr);
6572		}
6573		retval = 1;
6574		goto bailout;
6575	}
6576
6577	/* XXX KDM print out something here for success? */
6578bailout:
6579	if (ccb != NULL)
6580		cam_freeccb(ccb);
6581
6582	if (request != NULL)
6583		free(request);
6584
6585	if (response != NULL)
6586		free(response);
6587
6588	return (retval);
6589}
6590
6591static int
6592smpmaninfo(struct cam_device *device, int argc, char **argv,
6593	   char *combinedopt, int retry_count, int timeout)
6594{
6595	union ccb *ccb;
6596	struct smp_report_manuf_info_request request;
6597	struct smp_report_manuf_info_response response;
6598	struct sbuf *sb = NULL;
6599	int long_response = 0;
6600	int retval = 0;
6601	int c;
6602
6603	/*
6604	 * Note that at the moment we don't support sending SMP CCBs to
6605	 * devices that aren't probed by CAM.
6606	 */
6607	ccb = cam_getccb(device);
6608	if (ccb == NULL) {
6609		warnx("%s: error allocating CCB", __func__);
6610		return (1);
6611	}
6612
6613	bzero(&(&ccb->ccb_h)[1],
6614	      sizeof(union ccb) - sizeof(struct ccb_hdr));
6615
6616	while ((c = getopt(argc, argv, combinedopt)) != -1) {
6617		switch (c) {
6618		case 'l':
6619			long_response = 1;
6620			break;
6621		default:
6622			break;
6623		}
6624	}
6625	bzero(&request, sizeof(request));
6626	bzero(&response, sizeof(response));
6627
6628	smp_report_manuf_info(&ccb->smpio,
6629			      retry_count,
6630			      /*cbfcnp*/ NULL,
6631			      &request,
6632			      sizeof(request),
6633			      (uint8_t *)&response,
6634			      sizeof(response),
6635			      long_response,
6636			      timeout);
6637
6638	if (((retval = cam_send_ccb(device, ccb)) < 0)
6639	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
6640		const char warnstr[] = "error sending command";
6641
6642		if (retval < 0)
6643			warn(warnstr);
6644		else
6645			warnx(warnstr);
6646
6647		if (arglist & CAM_ARG_VERBOSE) {
6648			cam_error_print(device, ccb, CAM_ESF_ALL,
6649					CAM_EPF_ALL, stderr);
6650		}
6651		retval = 1;
6652		goto bailout;
6653	}
6654
6655	sb = sbuf_new_auto();
6656	if (sb == NULL) {
6657		warnx("%s: error allocating sbuf", __func__);
6658		goto bailout;
6659	}
6660
6661	smp_report_manuf_info_sbuf(&response, sizeof(response), sb);
6662
6663	if (sbuf_finish(sb) != 0) {
6664		warnx("%s: sbuf_finish", __func__);
6665		goto bailout;
6666	}
6667
6668	printf("%s", sbuf_data(sb));
6669
6670bailout:
6671
6672	if (ccb != NULL)
6673		cam_freeccb(ccb);
6674
6675	if (sb != NULL)
6676		sbuf_delete(sb);
6677
6678	return (retval);
6679}
6680
6681static int
6682getdevid(struct cam_devitem *item)
6683{
6684	int retval = 0;
6685	union ccb *ccb = NULL;
6686
6687	struct cam_device *dev;
6688
6689	dev = cam_open_btl(item->dev_match.path_id,
6690			   item->dev_match.target_id,
6691			   item->dev_match.target_lun, O_RDWR, NULL);
6692
6693	if (dev == NULL) {
6694		warnx("%s", cam_errbuf);
6695		retval = 1;
6696		goto bailout;
6697	}
6698
6699	item->device_id_len = 0;
6700
6701	ccb = cam_getccb(dev);
6702	if (ccb == NULL) {
6703		warnx("%s: error allocating CCB", __func__);
6704		retval = 1;
6705		goto bailout;
6706	}
6707
6708	bzero(&(&ccb->ccb_h)[1],
6709	      sizeof(union ccb) - sizeof(struct ccb_hdr));
6710
6711	/*
6712	 * On the first try, we just probe for the size of the data, and
6713	 * then allocate that much memory and try again.
6714	 */
6715retry:
6716	ccb->ccb_h.func_code = XPT_DEV_ADVINFO;
6717	ccb->ccb_h.flags = CAM_DIR_IN;
6718	ccb->cdai.flags = 0;
6719	ccb->cdai.buftype = CDAI_TYPE_SCSI_DEVID;
6720	ccb->cdai.bufsiz = item->device_id_len;
6721	if (item->device_id_len != 0)
6722		ccb->cdai.buf = (uint8_t *)item->device_id;
6723
6724	if (cam_send_ccb(dev, ccb) < 0) {
6725		warn("%s: error sending XPT_GDEV_ADVINFO CCB", __func__);
6726		retval = 1;
6727		goto bailout;
6728	}
6729
6730	if (ccb->ccb_h.status != CAM_REQ_CMP) {
6731		warnx("%s: CAM status %#x", __func__, ccb->ccb_h.status);
6732		retval = 1;
6733		goto bailout;
6734	}
6735
6736	if (item->device_id_len == 0) {
6737		/*
6738		 * This is our first time through.  Allocate the buffer,
6739		 * and then go back to get the data.
6740		 */
6741		if (ccb->cdai.provsiz == 0) {
6742			warnx("%s: invalid .provsiz field returned with "
6743			     "XPT_GDEV_ADVINFO CCB", __func__);
6744			retval = 1;
6745			goto bailout;
6746		}
6747		item->device_id_len = ccb->cdai.provsiz;
6748		item->device_id = malloc(item->device_id_len);
6749		if (item->device_id == NULL) {
6750			warn("%s: unable to allocate %d bytes", __func__,
6751			     item->device_id_len);
6752			retval = 1;
6753			goto bailout;
6754		}
6755		ccb->ccb_h.status = CAM_REQ_INPROG;
6756		goto retry;
6757	}
6758
6759bailout:
6760	if (dev != NULL)
6761		cam_close_device(dev);
6762
6763	if (ccb != NULL)
6764		cam_freeccb(ccb);
6765
6766	return (retval);
6767}
6768
6769/*
6770 * XXX KDM merge this code with getdevtree()?
6771 */
6772static int
6773buildbusdevlist(struct cam_devlist *devlist)
6774{
6775	union ccb ccb;
6776	int bufsize, fd = -1;
6777	struct dev_match_pattern *patterns;
6778	struct cam_devitem *item = NULL;
6779	int skip_device = 0;
6780	int retval = 0;
6781
6782	if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
6783		warn("couldn't open %s", XPT_DEVICE);
6784		return(1);
6785	}
6786
6787	bzero(&ccb, sizeof(union ccb));
6788
6789	ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
6790	ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
6791	ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
6792
6793	ccb.ccb_h.func_code = XPT_DEV_MATCH;
6794	bufsize = sizeof(struct dev_match_result) * 100;
6795	ccb.cdm.match_buf_len = bufsize;
6796	ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
6797	if (ccb.cdm.matches == NULL) {
6798		warnx("can't malloc memory for matches");
6799		close(fd);
6800		return(1);
6801	}
6802	ccb.cdm.num_matches = 0;
6803	ccb.cdm.num_patterns = 2;
6804	ccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern) *
6805		ccb.cdm.num_patterns;
6806
6807	patterns = (struct dev_match_pattern *)malloc(ccb.cdm.pattern_buf_len);
6808	if (patterns == NULL) {
6809		warnx("can't malloc memory for patterns");
6810		retval = 1;
6811		goto bailout;
6812	}
6813
6814	ccb.cdm.patterns = patterns;
6815	bzero(patterns, ccb.cdm.pattern_buf_len);
6816
6817	patterns[0].type = DEV_MATCH_DEVICE;
6818	patterns[0].pattern.device_pattern.flags = DEV_MATCH_PATH;
6819	patterns[0].pattern.device_pattern.path_id = devlist->path_id;
6820	patterns[1].type = DEV_MATCH_PERIPH;
6821	patterns[1].pattern.periph_pattern.flags = PERIPH_MATCH_PATH;
6822	patterns[1].pattern.periph_pattern.path_id = devlist->path_id;
6823
6824	/*
6825	 * We do the ioctl multiple times if necessary, in case there are
6826	 * more than 100 nodes in the EDT.
6827	 */
6828	do {
6829		unsigned int i;
6830
6831		if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
6832			warn("error sending CAMIOCOMMAND ioctl");
6833			retval = 1;
6834			goto bailout;
6835		}
6836
6837		if ((ccb.ccb_h.status != CAM_REQ_CMP)
6838		 || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
6839		    && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
6840			warnx("got CAM error %#x, CDM error %d\n",
6841			      ccb.ccb_h.status, ccb.cdm.status);
6842			retval = 1;
6843			goto bailout;
6844		}
6845
6846		for (i = 0; i < ccb.cdm.num_matches; i++) {
6847			switch (ccb.cdm.matches[i].type) {
6848			case DEV_MATCH_DEVICE: {
6849				struct device_match_result *dev_result;
6850
6851				dev_result =
6852				     &ccb.cdm.matches[i].result.device_result;
6853
6854				if (dev_result->flags &
6855				    DEV_RESULT_UNCONFIGURED) {
6856					skip_device = 1;
6857					break;
6858				} else
6859					skip_device = 0;
6860
6861				item = malloc(sizeof(*item));
6862				if (item == NULL) {
6863					warn("%s: unable to allocate %zd bytes",
6864					     __func__, sizeof(*item));
6865					retval = 1;
6866					goto bailout;
6867				}
6868				bzero(item, sizeof(*item));
6869				bcopy(dev_result, &item->dev_match,
6870				      sizeof(*dev_result));
6871				STAILQ_INSERT_TAIL(&devlist->dev_queue, item,
6872						   links);
6873
6874				if (getdevid(item) != 0) {
6875					retval = 1;
6876					goto bailout;
6877				}
6878				break;
6879			}
6880			case DEV_MATCH_PERIPH: {
6881				struct periph_match_result *periph_result;
6882
6883				periph_result =
6884				      &ccb.cdm.matches[i].result.periph_result;
6885
6886				if (skip_device != 0)
6887					break;
6888				item->num_periphs++;
6889				item->periph_matches = realloc(
6890					item->periph_matches,
6891					item->num_periphs *
6892					sizeof(struct periph_match_result));
6893				if (item->periph_matches == NULL) {
6894					warn("%s: error allocating periph "
6895					     "list", __func__);
6896					retval = 1;
6897					goto bailout;
6898				}
6899				bcopy(periph_result, &item->periph_matches[
6900				      item->num_periphs - 1],
6901				      sizeof(*periph_result));
6902				break;
6903			}
6904			default:
6905				fprintf(stderr, "%s: unexpected match "
6906					"type %d\n", __func__,
6907					ccb.cdm.matches[i].type);
6908				retval = 1;
6909				goto bailout;
6910				break; /*NOTREACHED*/
6911			}
6912		}
6913	} while ((ccb.ccb_h.status == CAM_REQ_CMP)
6914		&& (ccb.cdm.status == CAM_DEV_MATCH_MORE));
6915bailout:
6916
6917	if (fd != -1)
6918		close(fd);
6919
6920	free(patterns);
6921
6922	free(ccb.cdm.matches);
6923
6924	if (retval != 0)
6925		freebusdevlist(devlist);
6926
6927	return (retval);
6928}
6929
6930static void
6931freebusdevlist(struct cam_devlist *devlist)
6932{
6933	struct cam_devitem *item, *item2;
6934
6935	STAILQ_FOREACH_SAFE(item, &devlist->dev_queue, links, item2) {
6936		STAILQ_REMOVE(&devlist->dev_queue, item, cam_devitem,
6937			      links);
6938		free(item->device_id);
6939		free(item->periph_matches);
6940		free(item);
6941	}
6942}
6943
6944static struct cam_devitem *
6945findsasdevice(struct cam_devlist *devlist, uint64_t sasaddr)
6946{
6947	struct cam_devitem *item;
6948
6949	STAILQ_FOREACH(item, &devlist->dev_queue, links) {
6950		struct scsi_vpd_id_descriptor *idd;
6951
6952		/*
6953		 * XXX KDM look for LUN IDs as well?
6954		 */
6955		idd = scsi_get_devid(item->device_id,
6956					   item->device_id_len,
6957					   scsi_devid_is_sas_target);
6958		if (idd == NULL)
6959			continue;
6960
6961		if (scsi_8btou64(idd->identifier) == sasaddr)
6962			return (item);
6963	}
6964
6965	return (NULL);
6966}
6967
6968static int
6969smpphylist(struct cam_device *device, int argc, char **argv,
6970	   char *combinedopt, int retry_count, int timeout)
6971{
6972	struct smp_report_general_request *rgrequest = NULL;
6973	struct smp_report_general_response *rgresponse = NULL;
6974	struct smp_discover_request *disrequest = NULL;
6975	struct smp_discover_response *disresponse = NULL;
6976	struct cam_devlist devlist;
6977	union ccb *ccb;
6978	int long_response = 0;
6979	int num_phys = 0;
6980	int quiet = 0;
6981	int retval;
6982	int i, c;
6983
6984	/*
6985	 * Note that at the moment we don't support sending SMP CCBs to
6986	 * devices that aren't probed by CAM.
6987	 */
6988	ccb = cam_getccb(device);
6989	if (ccb == NULL) {
6990		warnx("%s: error allocating CCB", __func__);
6991		return (1);
6992	}
6993
6994	bzero(&(&ccb->ccb_h)[1],
6995	      sizeof(union ccb) - sizeof(struct ccb_hdr));
6996	STAILQ_INIT(&devlist.dev_queue);
6997
6998	rgrequest = malloc(sizeof(*rgrequest));
6999	if (rgrequest == NULL) {
7000		warn("%s: unable to allocate %zd bytes", __func__,
7001		     sizeof(*rgrequest));
7002		retval = 1;
7003		goto bailout;
7004	}
7005
7006	rgresponse = malloc(sizeof(*rgresponse));
7007	if (rgresponse == NULL) {
7008		warn("%s: unable to allocate %zd bytes", __func__,
7009		     sizeof(*rgresponse));
7010		retval = 1;
7011		goto bailout;
7012	}
7013
7014	while ((c = getopt(argc, argv, combinedopt)) != -1) {
7015		switch (c) {
7016		case 'l':
7017			long_response = 1;
7018			break;
7019		case 'q':
7020			quiet = 1;
7021			break;
7022		default:
7023			break;
7024		}
7025	}
7026
7027	smp_report_general(&ccb->smpio,
7028			   retry_count,
7029			   /*cbfcnp*/ NULL,
7030			   rgrequest,
7031			   /*request_len*/ sizeof(*rgrequest),
7032			   (uint8_t *)rgresponse,
7033			   /*response_len*/ sizeof(*rgresponse),
7034			   /*long_response*/ long_response,
7035			   timeout);
7036
7037	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
7038
7039	if (((retval = cam_send_ccb(device, ccb)) < 0)
7040	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
7041		const char warnstr[] = "error sending command";
7042
7043		if (retval < 0)
7044			warn(warnstr);
7045		else
7046			warnx(warnstr);
7047
7048		if (arglist & CAM_ARG_VERBOSE) {
7049			cam_error_print(device, ccb, CAM_ESF_ALL,
7050					CAM_EPF_ALL, stderr);
7051		}
7052		retval = 1;
7053		goto bailout;
7054	}
7055
7056	num_phys = rgresponse->num_phys;
7057
7058	if (num_phys == 0) {
7059		if (quiet == 0)
7060			fprintf(stdout, "%s: No Phys reported\n", __func__);
7061		retval = 1;
7062		goto bailout;
7063	}
7064
7065	devlist.path_id = device->path_id;
7066
7067	retval = buildbusdevlist(&devlist);
7068	if (retval != 0)
7069		goto bailout;
7070
7071	if (quiet == 0) {
7072		fprintf(stdout, "%d PHYs:\n", num_phys);
7073		fprintf(stdout, "PHY  Attached SAS Address\n");
7074	}
7075
7076	disrequest = malloc(sizeof(*disrequest));
7077	if (disrequest == NULL) {
7078		warn("%s: unable to allocate %zd bytes", __func__,
7079		     sizeof(*disrequest));
7080		retval = 1;
7081		goto bailout;
7082	}
7083
7084	disresponse = malloc(sizeof(*disresponse));
7085	if (disresponse == NULL) {
7086		warn("%s: unable to allocate %zd bytes", __func__,
7087		     sizeof(*disresponse));
7088		retval = 1;
7089		goto bailout;
7090	}
7091
7092	for (i = 0; i < num_phys; i++) {
7093		struct cam_devitem *item;
7094		struct device_match_result *dev_match;
7095		char vendor[16], product[48], revision[16];
7096		char tmpstr[256];
7097		int j;
7098
7099		bzero(&(&ccb->ccb_h)[1],
7100		      sizeof(union ccb) - sizeof(struct ccb_hdr));
7101
7102		ccb->ccb_h.status = CAM_REQ_INPROG;
7103		ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
7104
7105		smp_discover(&ccb->smpio,
7106			     retry_count,
7107			     /*cbfcnp*/ NULL,
7108			     disrequest,
7109			     sizeof(*disrequest),
7110			     (uint8_t *)disresponse,
7111			     sizeof(*disresponse),
7112			     long_response,
7113			     /*ignore_zone_group*/ 0,
7114			     /*phy*/ i,
7115			     timeout);
7116
7117		if (((retval = cam_send_ccb(device, ccb)) < 0)
7118		 || (((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
7119		  && (disresponse->function_result != SMP_FR_PHY_VACANT))) {
7120			const char warnstr[] = "error sending command";
7121
7122			if (retval < 0)
7123				warn(warnstr);
7124			else
7125				warnx(warnstr);
7126
7127			if (arglist & CAM_ARG_VERBOSE) {
7128				cam_error_print(device, ccb, CAM_ESF_ALL,
7129						CAM_EPF_ALL, stderr);
7130			}
7131			retval = 1;
7132			goto bailout;
7133		}
7134
7135		if (disresponse->function_result == SMP_FR_PHY_VACANT) {
7136			if (quiet == 0)
7137				fprintf(stdout, "%3d  <vacant>\n", i);
7138			continue;
7139		}
7140
7141		if (disresponse->attached_device == SMP_DIS_AD_TYPE_NONE) {
7142			item = NULL;
7143		} else {
7144			item = findsasdevice(&devlist,
7145			    scsi_8btou64(disresponse->attached_sas_address));
7146		}
7147
7148		if ((quiet == 0)
7149		 || (item != NULL)) {
7150			fprintf(stdout, "%3d  0x%016jx", i,
7151				(uintmax_t)scsi_8btou64(
7152				disresponse->attached_sas_address));
7153			if (item == NULL) {
7154				fprintf(stdout, "\n");
7155				continue;
7156			}
7157		} else if (quiet != 0)
7158			continue;
7159
7160		dev_match = &item->dev_match;
7161
7162		if (dev_match->protocol == PROTO_SCSI) {
7163			cam_strvis(vendor, dev_match->inq_data.vendor,
7164				   sizeof(dev_match->inq_data.vendor),
7165				   sizeof(vendor));
7166			cam_strvis(product, dev_match->inq_data.product,
7167				   sizeof(dev_match->inq_data.product),
7168				   sizeof(product));
7169			cam_strvis(revision, dev_match->inq_data.revision,
7170				   sizeof(dev_match->inq_data.revision),
7171				   sizeof(revision));
7172			sprintf(tmpstr, "<%s %s %s>", vendor, product,
7173				revision);
7174		} else if ((dev_match->protocol == PROTO_ATA)
7175			|| (dev_match->protocol == PROTO_SATAPM)) {
7176			cam_strvis(product, dev_match->ident_data.model,
7177				   sizeof(dev_match->ident_data.model),
7178				   sizeof(product));
7179			cam_strvis(revision, dev_match->ident_data.revision,
7180				   sizeof(dev_match->ident_data.revision),
7181				   sizeof(revision));
7182			sprintf(tmpstr, "<%s %s>", product, revision);
7183		} else {
7184			sprintf(tmpstr, "<>");
7185		}
7186		fprintf(stdout, "   %-33s ", tmpstr);
7187
7188		/*
7189		 * If we have 0 periphs, that's a bug...
7190		 */
7191		if (item->num_periphs == 0) {
7192			fprintf(stdout, "\n");
7193			continue;
7194		}
7195
7196		fprintf(stdout, "(");
7197		for (j = 0; j < item->num_periphs; j++) {
7198			if (j > 0)
7199				fprintf(stdout, ",");
7200
7201			fprintf(stdout, "%s%d",
7202				item->periph_matches[j].periph_name,
7203				item->periph_matches[j].unit_number);
7204
7205		}
7206		fprintf(stdout, ")\n");
7207	}
7208bailout:
7209	if (ccb != NULL)
7210		cam_freeccb(ccb);
7211
7212	free(rgrequest);
7213
7214	free(rgresponse);
7215
7216	free(disrequest);
7217
7218	free(disresponse);
7219
7220	freebusdevlist(&devlist);
7221
7222	return (retval);
7223}
7224
7225static int
7226atapm(struct cam_device *device, int argc, char **argv,
7227		 char *combinedopt, int retry_count, int timeout)
7228{
7229	union ccb *ccb;
7230	int retval = 0;
7231	int t = -1;
7232	int c;
7233	u_char cmd, sc;
7234
7235	ccb = cam_getccb(device);
7236
7237	if (ccb == NULL) {
7238		warnx("%s: error allocating ccb", __func__);
7239		return (1);
7240	}
7241
7242	while ((c = getopt(argc, argv, combinedopt)) != -1) {
7243		switch (c) {
7244		case 't':
7245			t = atoi(optarg);
7246			break;
7247		default:
7248			break;
7249		}
7250	}
7251	if (strcmp(argv[1], "idle") == 0) {
7252		if (t == -1)
7253			cmd = ATA_IDLE_IMMEDIATE;
7254		else
7255			cmd = ATA_IDLE_CMD;
7256	} else if (strcmp(argv[1], "standby") == 0) {
7257		if (t == -1)
7258			cmd = ATA_STANDBY_IMMEDIATE;
7259		else
7260			cmd = ATA_STANDBY_CMD;
7261	} else {
7262		cmd = ATA_SLEEP;
7263		t = -1;
7264	}
7265
7266	if (t < 0)
7267		sc = 0;
7268	else if (t <= (240 * 5))
7269		sc = (t + 4) / 5;
7270	else if (t <= (252 * 5))
7271		/* special encoding for 21 minutes */
7272		sc = 252;
7273	else if (t <= (11 * 30 * 60))
7274		sc = (t - 1) / (30 * 60) + 241;
7275	else
7276		sc = 253;
7277
7278	cam_fill_ataio(&ccb->ataio,
7279		      retry_count,
7280		      NULL,
7281		      /*flags*/CAM_DIR_NONE,
7282		      MSG_SIMPLE_Q_TAG,
7283		      /*data_ptr*/NULL,
7284		      /*dxfer_len*/0,
7285		      timeout ? timeout : 30 * 1000);
7286	ata_28bit_cmd(&ccb->ataio, cmd, 0, 0, sc);
7287
7288	/* Disable freezing the device queue */
7289	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
7290
7291	if (arglist & CAM_ARG_ERR_RECOVER)
7292		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
7293
7294	if (cam_send_ccb(device, ccb) < 0) {
7295		warn("error sending command");
7296
7297		if (arglist & CAM_ARG_VERBOSE)
7298			cam_error_print(device, ccb, CAM_ESF_ALL,
7299					CAM_EPF_ALL, stderr);
7300
7301		retval = 1;
7302		goto bailout;
7303	}
7304
7305	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
7306		cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
7307		retval = 1;
7308		goto bailout;
7309	}
7310bailout:
7311	cam_freeccb(ccb);
7312	return (retval);
7313}
7314
7315#endif /* MINIMALISTIC */
7316
7317void
7318usage(int printlong)
7319{
7320
7321	fprintf(printlong ? stdout : stderr,
7322"usage:  camcontrol <command>  [device id][generic args][command args]\n"
7323"        camcontrol devlist    [-v]\n"
7324#ifndef MINIMALISTIC
7325"        camcontrol periphlist [dev_id][-n dev_name] [-u unit]\n"
7326"        camcontrol tur        [dev_id][generic args]\n"
7327"        camcontrol inquiry    [dev_id][generic args] [-D] [-S] [-R]\n"
7328"        camcontrol identify   [dev_id][generic args] [-v]\n"
7329"        camcontrol reportluns [dev_id][generic args] [-c] [-l] [-r report]\n"
7330"        camcontrol readcap    [dev_id][generic args] [-b] [-h] [-H] [-N]\n"
7331"                              [-q] [-s]\n"
7332"        camcontrol start      [dev_id][generic args]\n"
7333"        camcontrol stop       [dev_id][generic args]\n"
7334"        camcontrol load       [dev_id][generic args]\n"
7335"        camcontrol eject      [dev_id][generic args]\n"
7336#endif /* MINIMALISTIC */
7337"        camcontrol rescan     <all | bus[:target:lun]>\n"
7338"        camcontrol reset      <all | bus[:target:lun]>\n"
7339#ifndef MINIMALISTIC
7340"        camcontrol defects    [dev_id][generic args] <-f format> [-P][-G]\n"
7341"        camcontrol modepage   [dev_id][generic args] <-m page | -l>\n"
7342"                              [-P pagectl][-e | -b][-d]\n"
7343"        camcontrol cmd        [dev_id][generic args]\n"
7344"                              <-a cmd [args] | -c cmd [args]>\n"
7345"                              [-d] [-f] [-i len fmt|-o len fmt [args]] [-r fmt]\n"
7346"        camcontrol smpcmd     [dev_id][generic args]\n"
7347"                              <-r len fmt [args]> <-R len fmt [args]>\n"
7348"        camcontrol smprg      [dev_id][generic args][-l]\n"
7349"        camcontrol smppc      [dev_id][generic args] <-p phy> [-l]\n"
7350"                              [-o operation][-d name][-m rate][-M rate]\n"
7351"                              [-T pp_timeout][-a enable|disable]\n"
7352"                              [-A enable|disable][-s enable|disable]\n"
7353"                              [-S enable|disable]\n"
7354"        camcontrol smpphylist [dev_id][generic args][-l][-q]\n"
7355"        camcontrol smpmaninfo [dev_id][generic args][-l]\n"
7356"        camcontrol debug      [-I][-P][-T][-S][-X][-c]\n"
7357"                              <all|bus[:target[:lun]]|off>\n"
7358"        camcontrol tags       [dev_id][generic args] [-N tags] [-q] [-v]\n"
7359"        camcontrol negotiate  [dev_id][generic args] [-a][-c]\n"
7360"                              [-D <enable|disable>][-M mode][-O offset]\n"
7361"                              [-q][-R syncrate][-v][-T <enable|disable>]\n"
7362"                              [-U][-W bus_width]\n"
7363"        camcontrol format     [dev_id][generic args][-q][-r][-w][-y]\n"
7364"        camcontrol idle       [dev_id][generic args][-t time]\n"
7365"        camcontrol standby    [dev_id][generic args][-t time]\n"
7366"        camcontrol sleep      [dev_id][generic args]\n"
7367"        camcontrol fwdownload [dev_id][generic args] <-f fw_image> [-y][-s]\n"
7368"        camcontrol security   [dev_id][generic args]\n"
7369"                              <-d pwd | -e pwd | -f | -h pwd | -k pwd>\n"
7370"                              [-l <high|maximum>] [-q] [-s pwd] [-T timeout]\n"
7371"                              [-U <user|master>] [-y]\n"
7372"        camcontrol hpa        [dev_id][generic args] [-f] [-l] [-P] [-p pwd]\n"
7373"                              [-q] [-s max_sectors] [-U pwd] [-y]\n"
7374#endif /* MINIMALISTIC */
7375"        camcontrol help\n");
7376	if (!printlong)
7377		return;
7378#ifndef MINIMALISTIC
7379	fprintf(stdout,
7380"Specify one of the following options:\n"
7381"devlist     list all CAM devices\n"
7382"periphlist  list all CAM peripheral drivers attached to a device\n"
7383"tur         send a test unit ready to the named device\n"
7384"inquiry     send a SCSI inquiry command to the named device\n"
7385"identify    send a ATA identify command to the named device\n"
7386"reportluns  send a SCSI report luns command to the device\n"
7387"readcap     send a SCSI read capacity command to the device\n"
7388"start       send a Start Unit command to the device\n"
7389"stop        send a Stop Unit command to the device\n"
7390"load        send a Start Unit command to the device with the load bit set\n"
7391"eject       send a Stop Unit command to the device with the eject bit set\n"
7392"rescan      rescan all busses, the given bus, or bus:target:lun\n"
7393"reset       reset all busses, the given bus, or bus:target:lun\n"
7394"defects     read the defect list of the specified device\n"
7395"modepage    display or edit (-e) the given mode page\n"
7396"cmd         send the given SCSI command, may need -i or -o as well\n"
7397"smpcmd      send the given SMP command, requires -o and -i\n"
7398"smprg       send the SMP Report General command\n"
7399"smppc       send the SMP PHY Control command, requires -p\n"
7400"smpphylist  display phys attached to a SAS expander\n"
7401"smpmaninfo  send the SMP Report Manufacturer Info command\n"
7402"debug       turn debugging on/off for a bus, target, or lun, or all devices\n"
7403"tags        report or set the number of transaction slots for a device\n"
7404"negotiate   report or set device negotiation parameters\n"
7405"format      send the SCSI FORMAT UNIT command to the named device\n"
7406"idle        send the ATA IDLE command to the named device\n"
7407"standby     send the ATA STANDBY command to the named device\n"
7408"sleep       send the ATA SLEEP command to the named device\n"
7409"fwdownload  program firmware of the named device with the given image"
7410"security    report or send ATA security commands to the named device\n"
7411"help        this message\n"
7412"Device Identifiers:\n"
7413"bus:target        specify the bus and target, lun defaults to 0\n"
7414"bus:target:lun    specify the bus, target and lun\n"
7415"deviceUNIT        specify the device name, like \"da4\" or \"cd2\"\n"
7416"Generic arguments:\n"
7417"-v                be verbose, print out sense information\n"
7418"-t timeout        command timeout in seconds, overrides default timeout\n"
7419"-n dev_name       specify device name, e.g. \"da\", \"cd\"\n"
7420"-u unit           specify unit number, e.g. \"0\", \"5\"\n"
7421"-E                have the kernel attempt to perform SCSI error recovery\n"
7422"-C count          specify the SCSI command retry count (needs -E to work)\n"
7423"modepage arguments:\n"
7424"-l                list all available mode pages\n"
7425"-m page           specify the mode page to view or edit\n"
7426"-e                edit the specified mode page\n"
7427"-b                force view to binary mode\n"
7428"-d                disable block descriptors for mode sense\n"
7429"-P pgctl          page control field 0-3\n"
7430"defects arguments:\n"
7431"-f format         specify defect list format (block, bfi or phys)\n"
7432"-G                get the grown defect list\n"
7433"-P                get the permanent defect list\n"
7434"inquiry arguments:\n"
7435"-D                get the standard inquiry data\n"
7436"-S                get the serial number\n"
7437"-R                get the transfer rate, etc.\n"
7438"reportluns arguments:\n"
7439"-c                only report a count of available LUNs\n"
7440"-l                only print out luns, and not a count\n"
7441"-r <reporttype>   specify \"default\", \"wellknown\" or \"all\"\n"
7442"readcap arguments\n"
7443"-b                only report the blocksize\n"
7444"-h                human readable device size, base 2\n"
7445"-H                human readable device size, base 10\n"
7446"-N                print the number of blocks instead of last block\n"
7447"-q                quiet, print numbers only\n"
7448"-s                only report the last block/device size\n"
7449"cmd arguments:\n"
7450"-c cdb [args]     specify the SCSI CDB\n"
7451"-i len fmt        specify input data and input data format\n"
7452"-o len fmt [args] specify output data and output data fmt\n"
7453"smpcmd arguments:\n"
7454"-r len fmt [args] specify the SMP command to be sent\n"
7455"-R len fmt [args] specify SMP response format\n"
7456"smprg arguments:\n"
7457"-l                specify the long response format\n"
7458"smppc arguments:\n"
7459"-p phy            specify the PHY to operate on\n"
7460"-l                specify the long request/response format\n"
7461"-o operation      specify the phy control operation\n"
7462"-d name           set the attached device name\n"
7463"-m rate           set the minimum physical link rate\n"
7464"-M rate           set the maximum physical link rate\n"
7465"-T pp_timeout     set the partial pathway timeout value\n"
7466"-a enable|disable enable or disable SATA slumber\n"
7467"-A enable|disable enable or disable SATA partial phy power\n"
7468"-s enable|disable enable or disable SAS slumber\n"
7469"-S enable|disable enable or disable SAS partial phy power\n"
7470"smpphylist arguments:\n"
7471"-l                specify the long response format\n"
7472"-q                only print phys with attached devices\n"
7473"smpmaninfo arguments:\n"
7474"-l                specify the long response format\n"
7475"debug arguments:\n"
7476"-I                CAM_DEBUG_INFO -- scsi commands, errors, data\n"
7477"-T                CAM_DEBUG_TRACE -- routine flow tracking\n"
7478"-S                CAM_DEBUG_SUBTRACE -- internal routine command flow\n"
7479"-c                CAM_DEBUG_CDB -- print out SCSI CDBs only\n"
7480"tags arguments:\n"
7481"-N tags           specify the number of tags to use for this device\n"
7482"-q                be quiet, don't report the number of tags\n"
7483"-v                report a number of tag-related parameters\n"
7484"negotiate arguments:\n"
7485"-a                send a test unit ready after negotiation\n"
7486"-c                report/set current negotiation settings\n"
7487"-D <arg>          \"enable\" or \"disable\" disconnection\n"
7488"-M mode           set ATA mode\n"
7489"-O offset         set command delay offset\n"
7490"-q                be quiet, don't report anything\n"
7491"-R syncrate       synchronization rate in MHz\n"
7492"-T <arg>          \"enable\" or \"disable\" tagged queueing\n"
7493"-U                report/set user negotiation settings\n"
7494"-W bus_width      set the bus width in bits (8, 16 or 32)\n"
7495"-v                also print a Path Inquiry CCB for the controller\n"
7496"format arguments:\n"
7497"-q                be quiet, don't print status messages\n"
7498"-r                run in report only mode\n"
7499"-w                don't send immediate format command\n"
7500"-y                don't ask any questions\n"
7501"idle/standby arguments:\n"
7502"-t <arg>          number of seconds before respective state.\n"
7503"fwdownload arguments:\n"
7504"-f fw_image       path to firmware image file\n"
7505"-y                don't ask any questions\n"
7506"-s                run in simulation mode\n"
7507"-v                print info for every firmware segment sent to device\n"
7508"security arguments:\n"
7509"-d pwd            disable security using the given password for the selected\n"
7510"                  user\n"
7511"-e pwd            erase the device using the given pwd for the selected user\n"
7512"-f                freeze the security configuration of the specified device\n"
7513"-h pwd            enhanced erase the device using the given pwd for the\n"
7514"                  selected user\n"
7515"-k pwd            unlock the device using the given pwd for the selected\n"
7516"                  user\n"
7517"-l <high|maximum> specifies which security level to set: high or maximum\n"
7518"-q                be quiet, do not print any status messages\n"
7519"-s pwd            password the device (enable security) using the given\n"
7520"                  pwd for the selected user\n"
7521"-T timeout        overrides the timeout (seconds) used for erase operation\n"
7522"-U <user|master>  specifies which user to set: user or master\n"
7523"-y                don't ask any questions\n"
7524"hpa arguments:\n"
7525"-f                freeze the HPA configuration of the device\n"
7526"-l                lock the HPA configuration of the device\n"
7527"-P                make the HPA max sectors persist\n"
7528"-p pwd            Set the HPA configuration password required for unlock\n"
7529"                  calls\n"
7530"-q                be quiet, do not print any status messages\n"
7531"-s sectors        configures the maximum user accessible sectors of the\n"
7532"                  device\n"
7533"-U pwd            unlock the HPA configuration of the device\n"
7534"-y                don't ask any questions\n"
7535);
7536#endif /* MINIMALISTIC */
7537}
7538
7539int
7540main(int argc, char **argv)
7541{
7542	int c;
7543	char *device = NULL;
7544	int unit = 0;
7545	struct cam_device *cam_dev = NULL;
7546	int timeout = 0, retry_count = 1;
7547	camcontrol_optret optreturn;
7548	char *tstr;
7549	const char *mainopt = "C:En:t:u:v";
7550	const char *subopt = NULL;
7551	char combinedopt[256];
7552	int error = 0, optstart = 2;
7553	int devopen = 1;
7554#ifndef MINIMALISTIC
7555	int bus, target, lun;
7556#endif /* MINIMALISTIC */
7557
7558	cmdlist = CAM_CMD_NONE;
7559	arglist = CAM_ARG_NONE;
7560
7561	if (argc < 2) {
7562		usage(0);
7563		exit(1);
7564	}
7565
7566	/*
7567	 * Get the base option.
7568	 */
7569	optreturn = getoption(option_table,argv[1], &cmdlist, &arglist,&subopt);
7570
7571	if (optreturn == CC_OR_AMBIGUOUS) {
7572		warnx("ambiguous option %s", argv[1]);
7573		usage(0);
7574		exit(1);
7575	} else if (optreturn == CC_OR_NOT_FOUND) {
7576		warnx("option %s not found", argv[1]);
7577		usage(0);
7578		exit(1);
7579	}
7580
7581	/*
7582	 * Ahh, getopt(3) is a pain.
7583	 *
7584	 * This is a gross hack.  There really aren't many other good
7585	 * options (excuse the pun) for parsing options in a situation like
7586	 * this.  getopt is kinda braindead, so you end up having to run
7587	 * through the options twice, and give each invocation of getopt
7588	 * the option string for the other invocation.
7589	 *
7590	 * You would think that you could just have two groups of options.
7591	 * The first group would get parsed by the first invocation of
7592	 * getopt, and the second group would get parsed by the second
7593	 * invocation of getopt.  It doesn't quite work out that way.  When
7594	 * the first invocation of getopt finishes, it leaves optind pointing
7595	 * to the argument _after_ the first argument in the second group.
7596	 * So when the second invocation of getopt comes around, it doesn't
7597	 * recognize the first argument it gets and then bails out.
7598	 *
7599	 * A nice alternative would be to have a flag for getopt that says
7600	 * "just keep parsing arguments even when you encounter an unknown
7601	 * argument", but there isn't one.  So there's no real clean way to
7602	 * easily parse two sets of arguments without having one invocation
7603	 * of getopt know about the other.
7604	 *
7605	 * Without this hack, the first invocation of getopt would work as
7606	 * long as the generic arguments are first, but the second invocation
7607	 * (in the subfunction) would fail in one of two ways.  In the case
7608	 * where you don't set optreset, it would fail because optind may be
7609	 * pointing to the argument after the one it should be pointing at.
7610	 * In the case where you do set optreset, and reset optind, it would
7611	 * fail because getopt would run into the first set of options, which
7612	 * it doesn't understand.
7613	 *
7614	 * All of this would "sort of" work if you could somehow figure out
7615	 * whether optind had been incremented one option too far.  The
7616	 * mechanics of that, however, are more daunting than just giving
7617	 * both invocations all of the expect options for either invocation.
7618	 *
7619	 * Needless to say, I wouldn't mind if someone invented a better
7620	 * (non-GPL!) command line parsing interface than getopt.  I
7621	 * wouldn't mind if someone added more knobs to getopt to make it
7622	 * work better.  Who knows, I may talk myself into doing it someday,
7623	 * if the standards weenies let me.  As it is, it just leads to
7624	 * hackery like this and causes people to avoid it in some cases.
7625	 *
7626	 * KDM, September 8th, 1998
7627	 */
7628	if (subopt != NULL)
7629		sprintf(combinedopt, "%s%s", mainopt, subopt);
7630	else
7631		sprintf(combinedopt, "%s", mainopt);
7632
7633	/*
7634	 * For these options we do not parse optional device arguments and
7635	 * we do not open a passthrough device.
7636	 */
7637	if ((cmdlist == CAM_CMD_RESCAN)
7638	 || (cmdlist == CAM_CMD_RESET)
7639	 || (cmdlist == CAM_CMD_DEVTREE)
7640	 || (cmdlist == CAM_CMD_USAGE)
7641	 || (cmdlist == CAM_CMD_DEBUG))
7642		devopen = 0;
7643
7644#ifndef MINIMALISTIC
7645	if ((devopen == 1)
7646	 && (argc > 2 && argv[2][0] != '-')) {
7647		char name[30];
7648		int rv;
7649
7650		if (isdigit(argv[2][0])) {
7651			/* device specified as bus:target[:lun] */
7652			rv = parse_btl(argv[2], &bus, &target, &lun, &arglist);
7653			if (rv < 2)
7654				errx(1, "numeric device specification must "
7655				     "be either bus:target, or "
7656				     "bus:target:lun");
7657			/* default to 0 if lun was not specified */
7658			if ((arglist & CAM_ARG_LUN) == 0) {
7659				lun = 0;
7660				arglist |= CAM_ARG_LUN;
7661			}
7662			optstart++;
7663		} else {
7664			if (cam_get_device(argv[2], name, sizeof name, &unit)
7665			    == -1)
7666				errx(1, "%s", cam_errbuf);
7667			device = strdup(name);
7668			arglist |= CAM_ARG_DEVICE | CAM_ARG_UNIT;
7669			optstart++;
7670		}
7671	}
7672#endif /* MINIMALISTIC */
7673	/*
7674	 * Start getopt processing at argv[2/3], since we've already
7675	 * accepted argv[1..2] as the command name, and as a possible
7676	 * device name.
7677	 */
7678	optind = optstart;
7679
7680	/*
7681	 * Now we run through the argument list looking for generic
7682	 * options, and ignoring options that possibly belong to
7683	 * subfunctions.
7684	 */
7685	while ((c = getopt(argc, argv, combinedopt))!= -1){
7686		switch(c) {
7687			case 'C':
7688				retry_count = strtol(optarg, NULL, 0);
7689				if (retry_count < 0)
7690					errx(1, "retry count %d is < 0",
7691					     retry_count);
7692				arglist |= CAM_ARG_RETRIES;
7693				break;
7694			case 'E':
7695				arglist |= CAM_ARG_ERR_RECOVER;
7696				break;
7697			case 'n':
7698				arglist |= CAM_ARG_DEVICE;
7699				tstr = optarg;
7700				while (isspace(*tstr) && (*tstr != '\0'))
7701					tstr++;
7702				device = (char *)strdup(tstr);
7703				break;
7704			case 't':
7705				timeout = strtol(optarg, NULL, 0);
7706				if (timeout < 0)
7707					errx(1, "invalid timeout %d", timeout);
7708				/* Convert the timeout from seconds to ms */
7709				timeout *= 1000;
7710				arglist |= CAM_ARG_TIMEOUT;
7711				break;
7712			case 'u':
7713				arglist |= CAM_ARG_UNIT;
7714				unit = strtol(optarg, NULL, 0);
7715				break;
7716			case 'v':
7717				arglist |= CAM_ARG_VERBOSE;
7718				break;
7719			default:
7720				break;
7721		}
7722	}
7723
7724#ifndef MINIMALISTIC
7725	/*
7726	 * For most commands we'll want to open the passthrough device
7727	 * associated with the specified device.  In the case of the rescan
7728	 * commands, we don't use a passthrough device at all, just the
7729	 * transport layer device.
7730	 */
7731	if (devopen == 1) {
7732		if (((arglist & (CAM_ARG_BUS|CAM_ARG_TARGET)) == 0)
7733		 && (((arglist & CAM_ARG_DEVICE) == 0)
7734		  || ((arglist & CAM_ARG_UNIT) == 0))) {
7735			errx(1, "subcommand \"%s\" requires a valid device "
7736			     "identifier", argv[1]);
7737		}
7738
7739		if ((cam_dev = ((arglist & (CAM_ARG_BUS | CAM_ARG_TARGET))?
7740				cam_open_btl(bus, target, lun, O_RDWR, NULL) :
7741				cam_open_spec_device(device,unit,O_RDWR,NULL)))
7742		     == NULL)
7743			errx(1,"%s", cam_errbuf);
7744	}
7745#endif /* MINIMALISTIC */
7746
7747	/*
7748	 * Reset optind to 2, and reset getopt, so these routines can parse
7749	 * the arguments again.
7750	 */
7751	optind = optstart;
7752	optreset = 1;
7753
7754	switch(cmdlist) {
7755#ifndef MINIMALISTIC
7756		case CAM_CMD_DEVLIST:
7757			error = getdevlist(cam_dev);
7758			break;
7759		case CAM_CMD_HPA:
7760			error = atahpa(cam_dev, retry_count, timeout,
7761				       argc, argv, combinedopt);
7762			break;
7763#endif /* MINIMALISTIC */
7764		case CAM_CMD_DEVTREE:
7765			error = getdevtree();
7766			break;
7767#ifndef MINIMALISTIC
7768		case CAM_CMD_TUR:
7769			error = testunitready(cam_dev, retry_count, timeout, 0);
7770			break;
7771		case CAM_CMD_INQUIRY:
7772			error = scsidoinquiry(cam_dev, argc, argv, combinedopt,
7773					      retry_count, timeout);
7774			break;
7775		case CAM_CMD_IDENTIFY:
7776			error = ataidentify(cam_dev, retry_count, timeout);
7777			break;
7778		case CAM_CMD_STARTSTOP:
7779			error = scsistart(cam_dev, arglist & CAM_ARG_START_UNIT,
7780					  arglist & CAM_ARG_EJECT, retry_count,
7781					  timeout);
7782			break;
7783#endif /* MINIMALISTIC */
7784		case CAM_CMD_RESCAN:
7785			error = dorescan_or_reset(argc, argv, 1);
7786			break;
7787		case CAM_CMD_RESET:
7788			error = dorescan_or_reset(argc, argv, 0);
7789			break;
7790#ifndef MINIMALISTIC
7791		case CAM_CMD_READ_DEFECTS:
7792			error = readdefects(cam_dev, argc, argv, combinedopt,
7793					    retry_count, timeout);
7794			break;
7795		case CAM_CMD_MODE_PAGE:
7796			modepage(cam_dev, argc, argv, combinedopt,
7797				 retry_count, timeout);
7798			break;
7799		case CAM_CMD_SCSI_CMD:
7800			error = scsicmd(cam_dev, argc, argv, combinedopt,
7801					retry_count, timeout);
7802			break;
7803		case CAM_CMD_SMP_CMD:
7804			error = smpcmd(cam_dev, argc, argv, combinedopt,
7805				       retry_count, timeout);
7806			break;
7807		case CAM_CMD_SMP_RG:
7808			error = smpreportgeneral(cam_dev, argc, argv,
7809						 combinedopt, retry_count,
7810						 timeout);
7811			break;
7812		case CAM_CMD_SMP_PC:
7813			error = smpphycontrol(cam_dev, argc, argv, combinedopt,
7814					      retry_count, timeout);
7815			break;
7816		case CAM_CMD_SMP_PHYLIST:
7817			error = smpphylist(cam_dev, argc, argv, combinedopt,
7818					   retry_count, timeout);
7819			break;
7820		case CAM_CMD_SMP_MANINFO:
7821			error = smpmaninfo(cam_dev, argc, argv, combinedopt,
7822					   retry_count, timeout);
7823			break;
7824		case CAM_CMD_DEBUG:
7825			error = camdebug(argc, argv, combinedopt);
7826			break;
7827		case CAM_CMD_TAG:
7828			error = tagcontrol(cam_dev, argc, argv, combinedopt);
7829			break;
7830		case CAM_CMD_RATE:
7831			error = ratecontrol(cam_dev, retry_count, timeout,
7832					    argc, argv, combinedopt);
7833			break;
7834		case CAM_CMD_FORMAT:
7835			error = scsiformat(cam_dev, argc, argv,
7836					   combinedopt, retry_count, timeout);
7837			break;
7838		case CAM_CMD_REPORTLUNS:
7839			error = scsireportluns(cam_dev, argc, argv,
7840					       combinedopt, retry_count,
7841					       timeout);
7842			break;
7843		case CAM_CMD_READCAP:
7844			error = scsireadcapacity(cam_dev, argc, argv,
7845						 combinedopt, retry_count,
7846						 timeout);
7847			break;
7848		case CAM_CMD_IDLE:
7849		case CAM_CMD_STANDBY:
7850		case CAM_CMD_SLEEP:
7851			error = atapm(cam_dev, argc, argv,
7852				      combinedopt, retry_count, timeout);
7853			break;
7854		case CAM_CMD_SECURITY:
7855			error = atasecurity(cam_dev, retry_count, timeout,
7856					    argc, argv, combinedopt);
7857			break;
7858		case CAM_CMD_DOWNLOAD_FW:
7859			error = fwdownload(cam_dev, argc, argv, combinedopt,
7860			    arglist & CAM_ARG_VERBOSE, retry_count, timeout,
7861			    get_disk_type(cam_dev));
7862			break;
7863#endif /* MINIMALISTIC */
7864		case CAM_CMD_USAGE:
7865			usage(1);
7866			break;
7867		default:
7868			usage(0);
7869			error = 1;
7870			break;
7871	}
7872
7873	if (cam_dev != NULL)
7874		cam_close_device(cam_dev);
7875
7876	exit(error);
7877}
7878