xref: /dragonfly/sbin/camcontrol/camcontrol.c (revision 9b5ae8ee)
1 /*
2  * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2005, 2006 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  * $FreeBSD: src/sbin/camcontrol/camcontrol.c,v 1.21.2.13 2003/01/08 17:55:02 njl Exp $
29  * $DragonFly: src/sbin/camcontrol/camcontrol.c,v 1.9 2007/12/02 04:44:03 pavalos Exp $
30  */
31 
32 #include <sys/ioctl.h>
33 #include <sys/types.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39 #include <ctype.h>
40 #include <err.h>
41 
42 #include <cam/cam.h>
43 #include <cam/cam_debug.h>
44 #include <cam/cam_ccb.h>
45 #include <cam/scsi/scsi_all.h>
46 #include <cam/scsi/scsi_da.h>
47 #include <cam/scsi/scsi_pass.h>
48 #include <cam/scsi/scsi_message.h>
49 #include <camlib.h>
50 #include "camcontrol.h"
51 
52 typedef enum {
53 	CAM_CMD_NONE		= 0x00000000,
54 	CAM_CMD_DEVLIST		= 0x00000001,
55 	CAM_CMD_TUR		= 0x00000002,
56 	CAM_CMD_INQUIRY		= 0x00000003,
57 	CAM_CMD_STARTSTOP	= 0x00000004,
58 	CAM_CMD_RESCAN		= 0x00000005,
59 	CAM_CMD_READ_DEFECTS	= 0x00000006,
60 	CAM_CMD_MODE_PAGE	= 0x00000007,
61 	CAM_CMD_SCSI_CMD	= 0x00000008,
62 	CAM_CMD_DEVTREE		= 0x00000009,
63 	CAM_CMD_USAGE		= 0x0000000a,
64 	CAM_CMD_DEBUG		= 0x0000000b,
65 	CAM_CMD_RESET		= 0x0000000c,
66 	CAM_CMD_FORMAT		= 0x0000000d,
67 	CAM_CMD_TAG		= 0x0000000e,
68 	CAM_CMD_RATE		= 0x0000000f,
69 	CAM_CMD_DETACH		= 0x00000010,
70 	CAM_CMD_REPORTLUNS	= 0x00000011
71 } cam_cmdmask;
72 
73 typedef enum {
74 	CAM_ARG_NONE		= 0x00000000,
75 	CAM_ARG_VERBOSE		= 0x00000001,
76 	CAM_ARG_DEVICE		= 0x00000002,
77 	CAM_ARG_BUS		= 0x00000004,
78 	CAM_ARG_TARGET		= 0x00000008,
79 	CAM_ARG_LUN		= 0x00000010,
80 	CAM_ARG_EJECT		= 0x00000020,
81 	CAM_ARG_UNIT		= 0x00000040,
82 	CAM_ARG_FORMAT_BLOCK	= 0x00000080,
83 	CAM_ARG_FORMAT_BFI	= 0x00000100,
84 	CAM_ARG_FORMAT_PHYS	= 0x00000200,
85 	CAM_ARG_PLIST		= 0x00000400,
86 	CAM_ARG_GLIST		= 0x00000800,
87 	CAM_ARG_GET_SERIAL	= 0x00001000,
88 	CAM_ARG_GET_STDINQ	= 0x00002000,
89 	CAM_ARG_GET_XFERRATE	= 0x00004000,
90 	CAM_ARG_INQ_MASK	= 0x00007000,
91 	CAM_ARG_MODE_EDIT	= 0x00008000,
92 	CAM_ARG_PAGE_CNTL	= 0x00010000,
93 	CAM_ARG_TIMEOUT		= 0x00020000,
94 	CAM_ARG_CMD_IN		= 0x00040000,
95 	CAM_ARG_CMD_OUT		= 0x00080000,
96 	CAM_ARG_DBD		= 0x00100000,
97 	CAM_ARG_ERR_RECOVER	= 0x00200000,
98 	CAM_ARG_RETRIES		= 0x00400000,
99 	CAM_ARG_START_UNIT	= 0x00800000,
100 	CAM_ARG_DEBUG_INFO	= 0x01000000,
101 	CAM_ARG_DEBUG_TRACE	= 0x02000000,
102 	CAM_ARG_DEBUG_SUBTRACE	= 0x04000000,
103 	CAM_ARG_DEBUG_CDB	= 0x08000000,
104 	CAM_ARG_DEBUG_XPT	= 0x10000000,
105 	CAM_ARG_DEBUG_PERIPH	= 0x20000000,
106 } cam_argmask;
107 
108 struct camcontrol_opts {
109 	const char 	*optname;
110 	cam_cmdmask	cmdnum;
111 	cam_argmask	argnum;
112 	const char	*subopt;
113 };
114 
115 #ifndef MINIMALISTIC
116 static const char scsicmd_opts[] = "c:i:o:";
117 static const char readdefect_opts[] = "f:GP";
118 static const char negotiate_opts[] = "acD:O:qR:T:UW:";
119 #endif
120 
121 struct camcontrol_opts option_table[] = {
122 #ifndef MINIMALISTIC
123 	{"tur", CAM_CMD_TUR, CAM_ARG_NONE, NULL},
124 	{"inquiry", CAM_CMD_INQUIRY, CAM_ARG_NONE, "DSR"},
125 	{"start", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT, NULL},
126 	{"stop", CAM_CMD_STARTSTOP, CAM_ARG_NONE, NULL},
127 	{"load", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT | CAM_ARG_EJECT, NULL},
128 	{"eject", CAM_CMD_STARTSTOP, CAM_ARG_EJECT, NULL},
129 	{"reportluns", CAM_CMD_REPORTLUNS, CAM_ARG_NONE, "clr:"},
130 #endif /* MINIMALISTIC */
131 	{"rescan", CAM_CMD_RESCAN, CAM_ARG_NONE, NULL},
132 	{"reset", CAM_CMD_RESET, CAM_ARG_NONE, NULL},
133 #ifndef MINIMALISTIC
134 	{"cmd", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts},
135 	{"command", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts},
136 	{"defects", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts},
137 	{"defectlist", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts},
138 #endif /* MINIMALISTIC */
139 	{"devlist", CAM_CMD_DEVTREE, CAM_ARG_NONE, NULL},
140 #ifndef MINIMALISTIC
141 	{"periphlist", CAM_CMD_DEVLIST, CAM_ARG_NONE, NULL},
142 	{"modepage", CAM_CMD_MODE_PAGE, CAM_ARG_NONE, "bdelm:P:"},
143 	{"tags", CAM_CMD_TAG, CAM_ARG_NONE, "N:q"},
144 	{"negotiate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts},
145 	{"rate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts},
146 	{"debug", CAM_CMD_DEBUG, CAM_ARG_NONE, "IPTSXc"},
147 	{"format", CAM_CMD_FORMAT, CAM_ARG_NONE, "qrwy"},
148 #endif /* MINIMALISTIC */
149 	{"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
150 	{"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
151 	{"-h", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
152 	{NULL, 0, 0, NULL}
153 };
154 
155 typedef enum {
156 	CC_OR_NOT_FOUND,
157 	CC_OR_AMBIGUOUS,
158 	CC_OR_FOUND
159 } camcontrol_optret;
160 
161 cam_cmdmask cmdlist;
162 cam_argmask arglist;
163 int bus, target, lun;
164 
165 
166 camcontrol_optret	getoption(char *, cam_cmdmask *, cam_argmask *,
167 				  const char **);
168 #ifndef MINIMALISTIC
169 static int	getdevlist(struct cam_device *);
170 static int	getdevtree(void);
171 static int	testunitready(struct cam_device *, int, int, int);
172 static int	scsistart(struct cam_device *, int, int, int, int);
173 static int	scsidoinquiry(struct cam_device *, int, char **, char *, int,
174 		int);
175 static int	scsiinquiry(struct cam_device *, int, int);
176 static int	scsiserial(struct cam_device *, int, int);
177 static int	scsixferrate(struct cam_device *);
178 #endif /* MINIMALISTIC */
179 static int	parse_btl(char *, int *, int *, int *, cam_argmask *);
180 static int	dorescan_or_reset(int, char **, int);
181 static int	rescan_or_reset_bus(int, int);
182 static int	scanlun_or_reset_dev(int, int, int, int);
183 #ifndef MINIMALISTIC
184 static int	readdefects(struct cam_device *, int, char **, char *, int,
185 		int);
186 static void	modepage(struct cam_device *, int, char **, char *, int, int);
187 static int	scsicmd(struct cam_device *, int, char **, char *, int, int);
188 static int	tagcontrol(struct cam_device *, int, char **, char *);
189 static void	cts_print(struct cam_device *device,
190 		struct ccb_trans_settings *);
191 static void	cpi_print(struct ccb_pathinq *);
192 static int	get_cpi(struct cam_device *, struct ccb_pathinq *);
193 static int	get_print_cts(struct cam_device *, int, int,
194 			 struct ccb_trans_settings *);
195 static int	ratecontrol(struct cam_device *, int, int, int, char **,
196 		char *);
197 static int	scsiformat(struct cam_device *, int, char **, char *, int, int);
198 static int	scsireportluns(struct cam_device *device, int argc, char **argv,
199 			       char *combinedopt, int retry_count, int timeout);
200 #endif /* MINIMALISTIC */
201 
202 
203 camcontrol_optret
204 getoption(char *arg, cam_cmdmask *cmdnum, cam_argmask *argnum,
205 	  const char **subopt)
206 {
207 	struct camcontrol_opts *opts;
208 	int num_matches = 0;
209 
210 	for (opts = option_table; (opts != NULL) && (opts->optname != NULL);
211 	     opts++) {
212 		if (strncmp(opts->optname, arg, strlen(arg)) == 0) {
213 			*cmdnum = opts->cmdnum;
214 			*argnum = opts->argnum;
215 			*subopt = opts->subopt;
216 			if (++num_matches > 1)
217 				return(CC_OR_AMBIGUOUS);
218 		}
219 	}
220 
221 	if (num_matches > 0)
222 		return(CC_OR_FOUND);
223 	else
224 		return(CC_OR_NOT_FOUND);
225 }
226 
227 #ifndef MINIMALISTIC
228 static int
229 getdevlist(struct cam_device *device)
230 {
231 	union ccb *ccb;
232 	char status[32];
233 	int error = 0;
234 
235 	ccb = cam_getccb(device);
236 
237 	ccb->ccb_h.func_code = XPT_GDEVLIST;
238 	ccb->ccb_h.flags = CAM_DIR_NONE;
239 	ccb->ccb_h.retry_count = 1;
240 	ccb->cgdl.index = 0;
241 	ccb->cgdl.status = CAM_GDEVLIST_MORE_DEVS;
242 	while (ccb->cgdl.status == CAM_GDEVLIST_MORE_DEVS) {
243 		if (cam_send_ccb(device, ccb) < 0) {
244 			perror("error getting device list");
245 			cam_freeccb(ccb);
246 			return(1);
247 		}
248 
249 		status[0] = '\0';
250 
251 		switch (ccb->cgdl.status) {
252 			case CAM_GDEVLIST_MORE_DEVS:
253 				strcpy(status, "MORE");
254 				break;
255 			case CAM_GDEVLIST_LAST_DEVICE:
256 				strcpy(status, "LAST");
257 				break;
258 			case CAM_GDEVLIST_LIST_CHANGED:
259 				strcpy(status, "CHANGED");
260 				break;
261 			case CAM_GDEVLIST_ERROR:
262 				strcpy(status, "ERROR");
263 				error = 1;
264 				break;
265 		}
266 
267 		fprintf(stdout, "%s%d:  generation: %d index: %d status: %s\n",
268 			ccb->cgdl.periph_name,
269 			ccb->cgdl.unit_number,
270 			ccb->cgdl.generation,
271 			ccb->cgdl.index,
272 			status);
273 
274 		/*
275 		 * If the list has changed, we need to start over from the
276 		 * beginning.
277 		 */
278 		if (ccb->cgdl.status == CAM_GDEVLIST_LIST_CHANGED)
279 			ccb->cgdl.index = 0;
280 	}
281 
282 	cam_freeccb(ccb);
283 
284 	return(error);
285 }
286 #endif /* MINIMALISTIC */
287 
288 static int
289 getdevtree(void)
290 {
291 	union ccb ccb;
292 	int bufsize, fd;
293 	unsigned int i;
294 	int need_close = 0;
295 	int error = 0;
296 	int skip_device = 0;
297 
298 	if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
299 		warn("couldn't open %s", XPT_DEVICE);
300 		return(1);
301 	}
302 
303 	bzero(&ccb, sizeof(union ccb));
304 
305 	ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
306 	ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
307 	ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
308 
309 	ccb.ccb_h.func_code = XPT_DEV_MATCH;
310 	bufsize = sizeof(struct dev_match_result) * 100;
311 	ccb.cdm.match_buf_len = bufsize;
312 	ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
313 	if (ccb.cdm.matches == NULL) {
314 		warnx("can't malloc memory for matches");
315 		close(fd);
316 		return(1);
317 	}
318 	ccb.cdm.num_matches = 0;
319 
320 	/*
321 	 * We fetch all nodes, since we display most of them in the default
322 	 * case, and all in the verbose case.
323 	 */
324 	ccb.cdm.num_patterns = 0;
325 	ccb.cdm.pattern_buf_len = 0;
326 
327 	/*
328 	 * We do the ioctl multiple times if necessary, in case there are
329 	 * more than 100 nodes in the EDT.
330 	 */
331 	do {
332 		if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
333 			warn("error sending CAMIOCOMMAND ioctl");
334 			error = 1;
335 			break;
336 		}
337 
338 		if ((ccb.ccb_h.status != CAM_REQ_CMP)
339 		 || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
340 		    && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
341 			warnx("got CAM error %#x, CDM error %d\n",
342 			      ccb.ccb_h.status, ccb.cdm.status);
343 			error = 1;
344 			break;
345 		}
346 
347 		for (i = 0; i < ccb.cdm.num_matches; i++) {
348 			switch (ccb.cdm.matches[i].type) {
349 			case DEV_MATCH_BUS: {
350 				struct bus_match_result *bus_result;
351 
352 				/*
353 				 * Only print the bus information if the
354 				 * user turns on the verbose flag.
355 				 */
356 				if ((arglist & CAM_ARG_VERBOSE) == 0)
357 					break;
358 
359 				bus_result =
360 					&ccb.cdm.matches[i].result.bus_result;
361 
362 				if (need_close) {
363 					fprintf(stdout, ")\n");
364 					need_close = 0;
365 				}
366 
367 				fprintf(stdout, "scbus%d on %s%d bus %d:\n",
368 					bus_result->path_id,
369 					bus_result->dev_name,
370 					bus_result->unit_number,
371 					bus_result->bus_id);
372 				break;
373 			}
374 			case DEV_MATCH_DEVICE: {
375 				struct device_match_result *dev_result;
376 				char vendor[16], product[48], revision[16];
377 				char tmpstr[256];
378 
379 				dev_result =
380 				     &ccb.cdm.matches[i].result.device_result;
381 
382 				if ((dev_result->flags
383 				     & DEV_RESULT_UNCONFIGURED)
384 				 && ((arglist & CAM_ARG_VERBOSE) == 0)) {
385 					skip_device = 1;
386 					break;
387 				} else
388 					skip_device = 0;
389 
390 				cam_strvis(vendor, dev_result->inq_data.vendor,
391 					   sizeof(dev_result->inq_data.vendor),
392 					   sizeof(vendor));
393 				cam_strvis(product,
394 					   dev_result->inq_data.product,
395 					   sizeof(dev_result->inq_data.product),
396 					   sizeof(product));
397 				cam_strvis(revision,
398 					   dev_result->inq_data.revision,
399 					  sizeof(dev_result->inq_data.revision),
400 					   sizeof(revision));
401 				sprintf(tmpstr, "<%s %s %s>", vendor, product,
402 					revision);
403 				if (need_close) {
404 					fprintf(stdout, ")\n");
405 					need_close = 0;
406 				}
407 
408 				fprintf(stdout, "%-33s  at scbus%d "
409 					"target %d lun %d (",
410 					tmpstr,
411 					dev_result->path_id,
412 					dev_result->target_id,
413 					dev_result->target_lun);
414 
415 				need_close = 1;
416 
417 				break;
418 			}
419 			case DEV_MATCH_PERIPH: {
420 				struct periph_match_result *periph_result;
421 
422 				periph_result =
423 				      &ccb.cdm.matches[i].result.periph_result;
424 
425 				if (skip_device != 0)
426 					break;
427 
428 				if (need_close > 1)
429 					fprintf(stdout, ",");
430 
431 				fprintf(stdout, "%s%d",
432 					periph_result->periph_name,
433 					periph_result->unit_number);
434 
435 				need_close++;
436 				break;
437 			}
438 			default:
439 				fprintf(stdout, "unknown match type\n");
440 				break;
441 			}
442 		}
443 
444 	} while ((ccb.ccb_h.status == CAM_REQ_CMP)
445 		&& (ccb.cdm.status == CAM_DEV_MATCH_MORE));
446 
447 	if (need_close)
448 		fprintf(stdout, ")\n");
449 
450 	close(fd);
451 
452 	return(error);
453 }
454 
455 #ifndef MINIMALISTIC
456 static int
457 testunitready(struct cam_device *device, int retry_count, int timeout,
458 	      int quiet)
459 {
460 	int error = 0;
461 	union ccb *ccb;
462 
463 	ccb = cam_getccb(device);
464 
465 	scsi_test_unit_ready(&ccb->csio,
466 			     /* retries */ retry_count,
467 			     /* cbfcnp */ NULL,
468 			     /* tag_action */ MSG_SIMPLE_Q_TAG,
469 			     /* sense_len */ SSD_FULL_SIZE,
470 			     /* timeout */ timeout ? timeout : 5000);
471 
472 	/* Disable freezing the device queue */
473 	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
474 
475 	if (arglist & CAM_ARG_ERR_RECOVER)
476 		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
477 
478 	if (cam_send_ccb(device, ccb) < 0) {
479 		if (quiet == 0)
480 			perror("error sending test unit ready");
481 
482 		if (arglist & CAM_ARG_VERBOSE) {
483 			cam_error_print(device, ccb, CAM_ESF_ALL,
484 					CAM_EPF_ALL, stderr);
485 		}
486 
487 		cam_freeccb(ccb);
488 		return(1);
489 	}
490 
491 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
492 		if (quiet == 0)
493 			fprintf(stdout, "Unit is ready\n");
494 	} else {
495 		if (quiet == 0)
496 			fprintf(stdout, "Unit is not ready\n");
497 		error = 1;
498 
499 		if (arglist & CAM_ARG_VERBOSE) {
500 			cam_error_print(device, ccb, CAM_ESF_ALL,
501 					CAM_EPF_ALL, stderr);
502 		}
503 	}
504 
505 	cam_freeccb(ccb);
506 
507 	return(error);
508 }
509 
510 static int
511 scsistart(struct cam_device *device, int startstop, int loadeject,
512 	  int retry_count, int timeout)
513 {
514 	union ccb *ccb;
515 	int error = 0;
516 
517 	ccb = cam_getccb(device);
518 
519 	/*
520 	 * If we're stopping, send an ordered tag so the drive in question
521 	 * will finish any previously queued writes before stopping.  If
522 	 * the device isn't capable of tagged queueing, or if tagged
523 	 * queueing is turned off, the tag action is a no-op.
524 	 */
525 	scsi_start_stop(&ccb->csio,
526 			/* retries */ retry_count,
527 			/* cbfcnp */ NULL,
528 			/* tag_action */ startstop ? MSG_SIMPLE_Q_TAG :
529 						     MSG_ORDERED_Q_TAG,
530 			/* start/stop */ startstop,
531 			/* load_eject */ loadeject,
532 			/* immediate */ 0,
533 			/* sense_len */ SSD_FULL_SIZE,
534 			/* timeout */ timeout ? timeout : 120000);
535 
536 	/* Disable freezing the device queue */
537 	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
538 
539 	if (arglist & CAM_ARG_ERR_RECOVER)
540 		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
541 
542 	if (cam_send_ccb(device, ccb) < 0) {
543 		perror("error sending start unit");
544 
545 		if (arglist & CAM_ARG_VERBOSE) {
546 			cam_error_print(device, ccb, CAM_ESF_ALL,
547 					CAM_EPF_ALL, stderr);
548 		}
549 
550 		cam_freeccb(ccb);
551 		return(1);
552 	}
553 
554 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
555 		if (startstop) {
556 			fprintf(stdout, "Unit started successfully");
557 			if (loadeject)
558 				fprintf(stdout,", Media loaded\n");
559 			else
560 				fprintf(stdout,"\n");
561 		} else {
562 			fprintf(stdout, "Unit stopped successfully");
563 			if (loadeject)
564 				fprintf(stdout, ", Media ejected\n");
565 			else
566 				fprintf(stdout, "\n");
567 		}
568 	else {
569 		error = 1;
570 		if (startstop)
571 			fprintf(stdout,
572 				"Error received from start unit command\n");
573 		else
574 			fprintf(stdout,
575 				"Error received from stop unit command\n");
576 
577 		if (arglist & CAM_ARG_VERBOSE) {
578 			cam_error_print(device, ccb, CAM_ESF_ALL,
579 					CAM_EPF_ALL, stderr);
580 		}
581 	}
582 
583 	cam_freeccb(ccb);
584 
585 	return(error);
586 }
587 
588 static int
589 scsidoinquiry(struct cam_device *device, int argc, char **argv,
590 	      char *combinedopt, int retry_count, int timeout)
591 {
592 	int c;
593 	int error = 0;
594 
595 	while ((c = getopt(argc, argv, combinedopt)) != -1) {
596 		switch(c) {
597 		case 'D':
598 			arglist |= CAM_ARG_GET_STDINQ;
599 			break;
600 		case 'R':
601 			arglist |= CAM_ARG_GET_XFERRATE;
602 			break;
603 		case 'S':
604 			arglist |= CAM_ARG_GET_SERIAL;
605 			break;
606 		default:
607 			break;
608 		}
609 	}
610 
611 	/*
612 	 * If the user didn't specify any inquiry options, he wants all of
613 	 * them.
614 	 */
615 	if ((arglist & CAM_ARG_INQ_MASK) == 0)
616 		arglist |= CAM_ARG_INQ_MASK;
617 
618 	if (arglist & CAM_ARG_GET_STDINQ)
619 		error = scsiinquiry(device, retry_count, timeout);
620 
621 	if (error != 0)
622 		return(error);
623 
624 	if (arglist & CAM_ARG_GET_SERIAL)
625 		scsiserial(device, retry_count, timeout);
626 
627 	if (error != 0)
628 		return(error);
629 
630 	if (arglist & CAM_ARG_GET_XFERRATE)
631 		error = scsixferrate(device);
632 
633 	return(error);
634 }
635 
636 static int
637 scsiinquiry(struct cam_device *device, int retry_count, int timeout)
638 {
639 	union ccb *ccb;
640 	struct scsi_inquiry_data *inq_buf;
641 	int error = 0;
642 
643 	ccb = cam_getccb(device);
644 
645 	if (ccb == NULL) {
646 		warnx("couldn't allocate CCB");
647 		return(1);
648 	}
649 
650 	/* cam_getccb cleans up the header, caller has to zero the payload */
651 	bzero(&(&ccb->ccb_h)[1],
652 	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
653 
654 	inq_buf = (struct scsi_inquiry_data *)malloc(
655 		sizeof(struct scsi_inquiry_data));
656 
657 	if (inq_buf == NULL) {
658 		cam_freeccb(ccb);
659 		warnx("can't malloc memory for inquiry\n");
660 		return(1);
661 	}
662 	bzero(inq_buf, sizeof(*inq_buf));
663 
664 	/*
665 	 * Note that although the size of the inquiry buffer is the full
666 	 * 256 bytes specified in the SCSI spec, we only tell the device
667 	 * that we have allocated SHORT_INQUIRY_LENGTH bytes.  There are
668 	 * two reasons for this:
669 	 *
670 	 *  - The SCSI spec says that when a length field is only 1 byte,
671 	 *    a value of 0 will be interpreted as 256.  Therefore
672 	 *    scsi_inquiry() will convert an inq_len (which is passed in as
673 	 *    a u_int32_t, but the field in the CDB is only 1 byte) of 256
674 	 *    to 0.  Evidently, very few devices meet the spec in that
675 	 *    regard.  Some devices, like many Seagate disks, take the 0 as
676 	 *    0, and don't return any data.  One Pioneer DVD-R drive
677 	 *    returns more data than the command asked for.
678 	 *
679 	 *    So, since there are numerous devices that just don't work
680 	 *    right with the full inquiry size, we don't send the full size.
681 	 *
682 	 *  - The second reason not to use the full inquiry data length is
683 	 *    that we don't need it here.  The only reason we issue a
684 	 *    standard inquiry is to get the vendor name, device name,
685 	 *    and revision so scsi_print_inquiry() can print them.
686 	 *
687 	 * If, at some point in the future, more inquiry data is needed for
688 	 * some reason, this code should use a procedure similar to the
689 	 * probe code.  i.e., issue a short inquiry, and determine from
690 	 * the additional length passed back from the device how much
691 	 * inquiry data the device supports.  Once the amount the device
692 	 * supports is determined, issue an inquiry for that amount and no
693 	 * more.
694 	 *
695 	 * KDM, 2/18/2000
696 	 */
697 	scsi_inquiry(&ccb->csio,
698 		     /* retries */ retry_count,
699 		     /* cbfcnp */ NULL,
700 		     /* tag_action */ MSG_SIMPLE_Q_TAG,
701 		     /* inq_buf */ (u_int8_t *)inq_buf,
702 		     /* inq_len */ SHORT_INQUIRY_LENGTH,
703 		     /* evpd */ 0,
704 		     /* page_code */ 0,
705 		     /* sense_len */ SSD_FULL_SIZE,
706 		     /* timeout */ timeout ? timeout : 5000);
707 
708 	/* Disable freezing the device queue */
709 	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
710 
711 	if (arglist & CAM_ARG_ERR_RECOVER)
712 		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
713 
714 	if (cam_send_ccb(device, ccb) < 0) {
715 		perror("error sending SCSI inquiry");
716 
717 		if (arglist & CAM_ARG_VERBOSE) {
718 			cam_error_print(device, ccb, CAM_ESF_ALL,
719 					CAM_EPF_ALL, stderr);
720 		}
721 
722 		cam_freeccb(ccb);
723 		return(1);
724 	}
725 
726 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
727 		error = 1;
728 
729 		if (arglist & CAM_ARG_VERBOSE) {
730 			cam_error_print(device, ccb, CAM_ESF_ALL,
731 					CAM_EPF_ALL, stderr);
732 		}
733 	}
734 
735 	cam_freeccb(ccb);
736 
737 	if (error != 0) {
738 		free(inq_buf);
739 		return(error);
740 	}
741 
742 	fprintf(stdout, "%s%d: ", device->device_name,
743 		device->dev_unit_num);
744 	scsi_print_inquiry(inq_buf);
745 
746 	free(inq_buf);
747 
748 	return(0);
749 }
750 
751 static int
752 scsiserial(struct cam_device *device, int retry_count, int timeout)
753 {
754 	union ccb *ccb;
755 	struct scsi_vpd_unit_serial_number *serial_buf;
756 	char serial_num[SVPD_SERIAL_NUM_SIZE + 1];
757 	int error = 0;
758 
759 	ccb = cam_getccb(device);
760 
761 	if (ccb == NULL) {
762 		warnx("couldn't allocate CCB");
763 		return(1);
764 	}
765 
766 	/* cam_getccb cleans up the header, caller has to zero the payload */
767 	bzero(&(&ccb->ccb_h)[1],
768 	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
769 
770 	serial_buf = (struct scsi_vpd_unit_serial_number *)
771 		malloc(sizeof(*serial_buf));
772 
773 	if (serial_buf == NULL) {
774 		cam_freeccb(ccb);
775 		warnx("can't malloc memory for serial number");
776 		return(1);
777 	}
778 
779 	scsi_inquiry(&ccb->csio,
780 		     /*retries*/ retry_count,
781 		     /*cbfcnp*/ NULL,
782 		     /* tag_action */ MSG_SIMPLE_Q_TAG,
783 		     /* inq_buf */ (u_int8_t *)serial_buf,
784 		     /* inq_len */ sizeof(*serial_buf),
785 		     /* evpd */ 1,
786 		     /* page_code */ SVPD_UNIT_SERIAL_NUMBER,
787 		     /* sense_len */ SSD_FULL_SIZE,
788 		     /* timeout */ timeout ? timeout : 5000);
789 
790 	/* Disable freezing the device queue */
791 	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
792 
793 	if (arglist & CAM_ARG_ERR_RECOVER)
794 		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
795 
796 	if (cam_send_ccb(device, ccb) < 0) {
797 		warn("error getting serial number");
798 
799 		if (arglist & CAM_ARG_VERBOSE) {
800 			cam_error_print(device, ccb, CAM_ESF_ALL,
801 					CAM_EPF_ALL, stderr);
802 		}
803 
804 		cam_freeccb(ccb);
805 		free(serial_buf);
806 		return(1);
807 	}
808 
809 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
810 		error = 1;
811 
812 		if (arglist & CAM_ARG_VERBOSE) {
813 			cam_error_print(device, ccb, CAM_ESF_ALL,
814 					CAM_EPF_ALL, stderr);
815 		}
816 	}
817 
818 	cam_freeccb(ccb);
819 
820 	if (error != 0) {
821 		free(serial_buf);
822 		return(error);
823 	}
824 
825 	bcopy(serial_buf->serial_num, serial_num, serial_buf->length);
826 	serial_num[serial_buf->length] = '\0';
827 
828 	if ((arglist & CAM_ARG_GET_STDINQ)
829 	 || (arglist & CAM_ARG_GET_XFERRATE))
830 		fprintf(stdout, "%s%d: Serial Number ",
831 			device->device_name, device->dev_unit_num);
832 
833 	fprintf(stdout, "%.60s\n", serial_num);
834 
835 	free(serial_buf);
836 
837 	return(0);
838 }
839 
840 static int
841 scsixferrate(struct cam_device *device)
842 {
843 	u_int32_t freq;
844 	u_int32_t speed;
845 	union ccb *ccb;
846 	u_int mb;
847 	int retval = 0;
848 
849 	ccb = cam_getccb(device);
850 
851 	if (ccb == NULL) {
852 		warnx("couldn't allocate CCB");
853 		return(1);
854 	}
855 
856 	bzero(&(&ccb->ccb_h)[1],
857 	      sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr));
858 
859 	ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
860 	ccb->cts.flags = CCB_TRANS_CURRENT_SETTINGS;
861 
862 	if (((retval = cam_send_ccb(device, ccb)) < 0)
863 	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
864 		const char error_string[] = "error getting transfer settings";
865 
866 		if (retval < 0)
867 			warn(error_string);
868 		else
869 			warnx(error_string);
870 
871 		if (arglist & CAM_ARG_VERBOSE)
872 			cam_error_print(device, ccb, CAM_ESF_ALL,
873 					CAM_EPF_ALL, stderr);
874 
875 		retval = 1;
876 
877 		goto xferrate_bailout;
878 
879 	}
880 
881 	if (((ccb->cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)
882 	 && (ccb->cts.sync_offset != 0)) {
883 		freq = scsi_calc_syncsrate(ccb->cts.sync_period);
884 		speed = freq;
885 	} else {
886 		struct ccb_pathinq cpi;
887 
888 		retval = get_cpi(device, &cpi);
889 
890 		if (retval != 0)
891 			goto xferrate_bailout;
892 
893 		speed = cpi.base_transfer_speed;
894 		freq = 0;
895 	}
896 
897 	fprintf(stdout, "%s%d: ", device->device_name,
898 		device->dev_unit_num);
899 
900 	if ((ccb->cts.valid & CCB_TRANS_BUS_WIDTH_VALID) != 0)
901 		speed *= (0x01 << device->bus_width);
902 
903 	mb = speed / 1000;
904 
905 	if (mb > 0)
906 		fprintf(stdout, "%d.%03dMB/s transfers ",
907 			mb, speed % 1000);
908 	else
909 		fprintf(stdout, "%dKB/s transfers ",
910 			speed);
911 
912 	if (((ccb->cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)
913 	 && (ccb->cts.sync_offset != 0))
914                 fprintf(stdout, "(%d.%03dMHz, offset %d", freq / 1000,
915 			freq % 1000, ccb->cts.sync_offset);
916 
917 	if (((ccb->cts.valid & CCB_TRANS_BUS_WIDTH_VALID) != 0)
918 	 && (ccb->cts.bus_width > 0)) {
919 		if (((ccb->cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)
920 		 && (ccb->cts.sync_offset != 0)) {
921 			fprintf(stdout, ", ");
922 		} else {
923 			fprintf(stdout, " (");
924 		}
925 		fprintf(stdout, "%dbit)", 8 * (0x01 << ccb->cts.bus_width));
926 	} else if (((ccb->cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)
927 		&& (ccb->cts.sync_offset != 0)) {
928 		fprintf(stdout, ")");
929 	}
930 
931 	if (((ccb->cts.valid & CCB_TRANS_TQ_VALID) != 0)
932 	 && (ccb->cts.flags & CCB_TRANS_TAG_ENB))
933                 fprintf(stdout, ", Tagged Queueing Enabled");
934 
935         fprintf(stdout, "\n");
936 
937 xferrate_bailout:
938 
939 	cam_freeccb(ccb);
940 
941 	return(retval);
942 }
943 #endif /* MINIMALISTIC */
944 
945 /*
946  * Parse out a bus, or a bus, target and lun in the following
947  * format:
948  * bus
949  * bus:target
950  * bus:target:lun
951  *
952  * Returns the number of parsed components, or 0.
953  */
954 static int
955 parse_btl(char *tstr, int *mybus, int *mytarget, int *mylun,
956 	  cam_argmask *myarglist)
957 {
958 	char *tmpstr;
959 	int convs = 0;
960 
961 	while (isspace(*tstr) && (*tstr != '\0'))
962 		tstr++;
963 
964 	tmpstr = (char *)strtok(tstr, ":");
965 	if ((tmpstr != NULL) && (*tmpstr != '\0')) {
966 		*mybus = strtol(tmpstr, NULL, 0);
967 		*myarglist |= CAM_ARG_BUS;
968 		convs++;
969 		tmpstr = (char *)strtok(NULL, ":");
970 		if ((tmpstr != NULL) && (*tmpstr != '\0')) {
971 			*mytarget = strtol(tmpstr, NULL, 0);
972 			*myarglist |= CAM_ARG_TARGET;
973 			convs++;
974 			tmpstr = (char *)strtok(NULL, ":");
975 			if ((tmpstr != NULL) && (*tmpstr != '\0')) {
976 				*mylun = strtol(tmpstr, NULL, 0);
977 				*myarglist |= CAM_ARG_LUN;
978 				convs++;
979 			}
980 		}
981 	}
982 
983 	return convs;
984 }
985 
986 static int
987 dorescan_or_reset(int argc, char **argv, int rescan)
988 {
989 	static const char must[] =
990 		"you must specify \"all\", a bus, or a bus:target:lun to %s";
991 	int rv, error = 0;
992 	int mybus = -1, mytarget = -1, mylun = -1;
993 	char *tstr;
994 
995 	if (argc < 3) {
996 		warnx(must, rescan? "rescan" : "reset");
997 		return(1);
998 	}
999 
1000 	tstr = argv[optind];
1001 	while (isspace(*tstr) && (*tstr != '\0'))
1002 		tstr++;
1003 	if (strncasecmp(tstr, "all", strlen("all")) == 0)
1004 		arglist |= CAM_ARG_BUS;
1005 	else {
1006 		rv = parse_btl(argv[optind], &mybus, &mytarget, &mylun,
1007 			       &arglist);
1008 		if (rv != 1 && rv != 3) {
1009 			warnx(must, rescan? "rescan" : "reset");
1010 			return(1);
1011 		}
1012 	}
1013 
1014 	if ((arglist & CAM_ARG_BUS)
1015 	    && (arglist & CAM_ARG_TARGET)
1016 	    && (arglist & CAM_ARG_LUN))
1017 		error = scanlun_or_reset_dev(mybus, mytarget, mylun, rescan);
1018 	else
1019 		error = rescan_or_reset_bus(mybus, rescan);
1020 
1021 	return(error);
1022 }
1023 
1024 static int
1025 rescan_or_reset_bus(int mybus, int rescan)
1026 {
1027 	union ccb ccb, matchccb;
1028 	int fd, retval;
1029 	int bufsize;
1030 
1031 	retval = 0;
1032 
1033 	if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
1034 		warnx("error opening transport layer device %s", XPT_DEVICE);
1035 		warn("%s", XPT_DEVICE);
1036 		return(1);
1037 	}
1038 
1039 	if (mybus != -1) {
1040 		ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS : XPT_RESET_BUS;
1041 		ccb.ccb_h.path_id = mybus;
1042 		ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
1043 		ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
1044 		ccb.crcn.flags = CAM_FLAG_NONE;
1045 
1046 		/* run this at a low priority */
1047 		ccb.ccb_h.pinfo.priority = 5;
1048 
1049 		if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
1050 			warn("CAMIOCOMMAND ioctl failed");
1051 			close(fd);
1052 			return(1);
1053 		}
1054 
1055 		if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
1056 			fprintf(stdout, "%s of bus %d was successful\n",
1057 			    rescan ? "Re-scan" : "Reset", mybus);
1058 		} else {
1059 			fprintf(stdout, "%s of bus %d returned error %#x\n",
1060 				rescan ? "Re-scan" : "Reset", mybus,
1061 				ccb.ccb_h.status & CAM_STATUS_MASK);
1062 			retval = 1;
1063 		}
1064 
1065 		close(fd);
1066 		return(retval);
1067 
1068 	}
1069 
1070 
1071 	/*
1072 	 * The right way to handle this is to modify the xpt so that it can
1073 	 * handle a wildcarded bus in a rescan or reset CCB.  At the moment
1074 	 * that isn't implemented, so instead we enumerate the busses and
1075 	 * send the rescan or reset to those busses in the case where the
1076 	 * given bus is -1 (wildcard).  We don't send a rescan or reset
1077 	 * to the xpt bus; sending a rescan to the xpt bus is effectively a
1078 	 * no-op, sending a rescan to the xpt bus would result in a status of
1079 	 * CAM_REQ_INVALID.
1080 	 */
1081 	bzero(&(&matchccb.ccb_h)[1],
1082 	      sizeof(struct ccb_dev_match) - sizeof(struct ccb_hdr));
1083 	matchccb.ccb_h.func_code = XPT_DEV_MATCH;
1084 	bufsize = sizeof(struct dev_match_result) * 20;
1085 	matchccb.cdm.match_buf_len = bufsize;
1086 	matchccb.cdm.matches=(struct dev_match_result *)malloc(bufsize);
1087 	if (matchccb.cdm.matches == NULL) {
1088 		warnx("can't malloc memory for matches");
1089 		retval = 1;
1090 		goto bailout;
1091 	}
1092 	matchccb.cdm.num_matches = 0;
1093 
1094 	matchccb.cdm.num_patterns = 1;
1095 	matchccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern);
1096 
1097 	matchccb.cdm.patterns = (struct dev_match_pattern *)malloc(
1098 		matchccb.cdm.pattern_buf_len);
1099 	if (matchccb.cdm.patterns == NULL) {
1100 		warnx("can't malloc memory for patterns");
1101 		retval = 1;
1102 		goto bailout;
1103 	}
1104 	matchccb.cdm.patterns[0].type = DEV_MATCH_BUS;
1105 	matchccb.cdm.patterns[0].pattern.bus_pattern.flags = BUS_MATCH_ANY;
1106 
1107 	do {
1108 		unsigned int i;
1109 
1110 		if (ioctl(fd, CAMIOCOMMAND, &matchccb) == -1) {
1111 			warn("CAMIOCOMMAND ioctl failed");
1112 			retval = 1;
1113 			goto bailout;
1114 		}
1115 
1116 		if ((matchccb.ccb_h.status != CAM_REQ_CMP)
1117 		 || ((matchccb.cdm.status != CAM_DEV_MATCH_LAST)
1118 		   && (matchccb.cdm.status != CAM_DEV_MATCH_MORE))) {
1119 			warnx("got CAM error %#x, CDM error %d\n",
1120 			      matchccb.ccb_h.status, matchccb.cdm.status);
1121 			retval = 1;
1122 			goto bailout;
1123 		}
1124 
1125 		for (i = 0; i < matchccb.cdm.num_matches; i++) {
1126 			struct bus_match_result *bus_result;
1127 
1128 			/* This shouldn't happen. */
1129 			if (matchccb.cdm.matches[i].type != DEV_MATCH_BUS)
1130 				continue;
1131 
1132 			bus_result = &matchccb.cdm.matches[i].result.bus_result;
1133 
1134 			/*
1135 			 * We don't want to rescan or reset the xpt bus.
1136 			 * See above.
1137 			 */
1138 			if ((int)bus_result->path_id == -1)
1139 				continue;
1140 
1141 			ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS :
1142 						       XPT_RESET_BUS;
1143 			ccb.ccb_h.path_id = bus_result->path_id;
1144 			ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
1145 			ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
1146 			ccb.crcn.flags = CAM_FLAG_NONE;
1147 
1148 			/* run this at a low priority */
1149 			ccb.ccb_h.pinfo.priority = 5;
1150 
1151 			if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
1152 				warn("CAMIOCOMMAND ioctl failed");
1153 				retval = 1;
1154 				goto bailout;
1155 			}
1156 
1157 			if ((ccb.ccb_h.status & CAM_STATUS_MASK) ==CAM_REQ_CMP){
1158 				fprintf(stdout, "%s of bus %d was successful\n",
1159 					rescan? "Re-scan" : "Reset",
1160 					bus_result->path_id);
1161 			} else {
1162 				/*
1163 				 * Don't bail out just yet, maybe the other
1164 				 * rescan or reset commands will complete
1165 				 * successfully.
1166 				 */
1167 				fprintf(stderr, "%s of bus %d returned error "
1168 					"%#x\n", rescan? "Re-scan" : "Reset",
1169 					bus_result->path_id,
1170 					ccb.ccb_h.status & CAM_STATUS_MASK);
1171 				retval = 1;
1172 			}
1173 		}
1174 	} while ((matchccb.ccb_h.status == CAM_REQ_CMP)
1175 		 && (matchccb.cdm.status == CAM_DEV_MATCH_MORE));
1176 
1177 bailout:
1178 
1179 	if (fd != -1)
1180 		close(fd);
1181 
1182 	if (matchccb.cdm.patterns != NULL)
1183 		free(matchccb.cdm.patterns);
1184 	if (matchccb.cdm.matches != NULL)
1185 		free(matchccb.cdm.matches);
1186 
1187 	return(retval);
1188 }
1189 
1190 static int
1191 scanlun_or_reset_dev(int mybus, int mytarget, int mylun, int scan)
1192 {
1193 	union ccb ccb;
1194 	struct cam_device *device;
1195 	int fd;
1196 
1197 	device = NULL;
1198 
1199 	if (mybus < 0) {
1200 		warnx("invalid bus number %d", mybus);
1201 		return(1);
1202 	}
1203 
1204 	if (mytarget < 0) {
1205 		warnx("invalid target number %d", mytarget);
1206 		return(1);
1207 	}
1208 
1209 	if (mylun < 0) {
1210 		warnx("invalid lun number %d", mylun);
1211 		return(1);
1212 	}
1213 
1214 	fd = -1;
1215 
1216 	bzero(&ccb, sizeof(union ccb));
1217 
1218 	if (scan) {
1219 		if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
1220 			warnx("error opening transport layer device %s\n",
1221 			    XPT_DEVICE);
1222 			warn("%s", XPT_DEVICE);
1223 			return(1);
1224 		}
1225 	} else {
1226 		device = cam_open_btl(mybus, mytarget, mylun, O_RDWR, NULL);
1227 		if (device == NULL) {
1228 			warnx("%s", cam_errbuf);
1229 			return(1);
1230 		}
1231 	}
1232 
1233 	ccb.ccb_h.func_code = (scan)? XPT_SCAN_LUN : XPT_RESET_DEV;
1234 	ccb.ccb_h.path_id = mybus;
1235 	ccb.ccb_h.target_id = mytarget;
1236 	ccb.ccb_h.target_lun = mylun;
1237 	ccb.ccb_h.timeout = 5000;
1238 	ccb.crcn.flags = CAM_FLAG_NONE;
1239 
1240 	/* run this at a low priority */
1241 	ccb.ccb_h.pinfo.priority = 5;
1242 
1243 	if (scan) {
1244 		if (ioctl(fd, CAMIOCOMMAND, &ccb) < 0) {
1245 			warn("CAMIOCOMMAND ioctl failed");
1246 			close(fd);
1247 			return(1);
1248 		}
1249 	} else {
1250 		if (cam_send_ccb(device, &ccb) < 0) {
1251 			warn("error sending XPT_RESET_DEV CCB");
1252 			cam_close_device(device);
1253 			return(1);
1254 		}
1255 	}
1256 
1257 	if (scan)
1258 		close(fd);
1259 	else
1260 		cam_close_device(device);
1261 
1262 	/*
1263 	 * An error code of CAM_BDR_SENT is normal for a BDR request.
1264 	 */
1265 	if (((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
1266 	 || ((!scan)
1267 	  && ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_BDR_SENT))) {
1268 		fprintf(stdout, "%s of %d:%d:%d was successful\n",
1269 		    scan? "Re-scan" : "Reset", mybus, mytarget, mylun);
1270 		return(0);
1271 	} else {
1272 		fprintf(stdout, "%s of %d:%d:%d returned error %#x\n",
1273 		    scan? "Re-scan" : "Reset", mybus, mytarget, mylun,
1274 		    ccb.ccb_h.status & CAM_STATUS_MASK);
1275 		return(1);
1276 	}
1277 }
1278 
1279 #ifndef MINIMALISTIC
1280 static int
1281 readdefects(struct cam_device *device, int argc, char **argv,
1282 	    char *combinedopt, int retry_count, int timeout)
1283 {
1284 	union ccb *ccb = NULL;
1285 	struct scsi_read_defect_data_10 *rdd_cdb;
1286 	u_int8_t *defect_list = NULL;
1287 	u_int32_t dlist_length = 65000;
1288 	u_int32_t returned_length = 0;
1289 	u_int32_t num_returned = 0;
1290 	u_int8_t returned_format;
1291 	unsigned int i;
1292 	int c, error = 0;
1293 	int lists_specified = 0;
1294 
1295 	while ((c = getopt(argc, argv, combinedopt)) != -1) {
1296 		switch(c){
1297 		case 'f':
1298 		{
1299 			char *tstr;
1300 			tstr = optarg;
1301 			while (isspace(*tstr) && (*tstr != '\0'))
1302 				tstr++;
1303 			if (strcmp(tstr, "block") == 0)
1304 				arglist |= CAM_ARG_FORMAT_BLOCK;
1305 			else if (strcmp(tstr, "bfi") == 0)
1306 				arglist |= CAM_ARG_FORMAT_BFI;
1307 			else if (strcmp(tstr, "phys") == 0)
1308 				arglist |= CAM_ARG_FORMAT_PHYS;
1309 			else {
1310 				error = 1;
1311 				warnx("invalid defect format %s", tstr);
1312 				goto defect_bailout;
1313 			}
1314 			break;
1315 		}
1316 		case 'G':
1317 			arglist |= CAM_ARG_GLIST;
1318 			break;
1319 		case 'P':
1320 			arglist |= CAM_ARG_PLIST;
1321 			break;
1322 		default:
1323 			break;
1324 		}
1325 	}
1326 
1327 	ccb = cam_getccb(device);
1328 
1329 	/*
1330 	 * Hopefully 65000 bytes is enough to hold the defect list.  If it
1331 	 * isn't, the disk is probably dead already.  We'd have to go with
1332 	 * 12 byte command (i.e. alloc_length is 32 bits instead of 16)
1333 	 * to hold them all.
1334 	 */
1335 	defect_list = malloc(dlist_length);
1336 	if (defect_list == NULL) {
1337 		warnx("can't malloc memory for defect list");
1338 		error = 1;
1339 		goto defect_bailout;
1340 	}
1341 
1342 	rdd_cdb =(struct scsi_read_defect_data_10 *)&ccb->csio.cdb_io.cdb_bytes;
1343 
1344 	/*
1345 	 * cam_getccb() zeros the CCB header only.  So we need to zero the
1346 	 * payload portion of the ccb.
1347 	 */
1348 	bzero(&(&ccb->ccb_h)[1],
1349 	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
1350 
1351 	cam_fill_csio(&ccb->csio,
1352 		      /*retries*/ retry_count,
1353 		      /*cbfcnp*/ NULL,
1354 		      /*flags*/ CAM_DIR_IN | ((arglist & CAM_ARG_ERR_RECOVER) ?
1355 					      CAM_PASS_ERR_RECOVER : 0),
1356 		      /*tag_action*/ MSG_SIMPLE_Q_TAG,
1357 		      /*data_ptr*/ defect_list,
1358 		      /*dxfer_len*/ dlist_length,
1359 		      /*sense_len*/ SSD_FULL_SIZE,
1360 		      /*cdb_len*/ sizeof(struct scsi_read_defect_data_10),
1361 		      /*timeout*/ timeout ? timeout : 5000);
1362 
1363 	rdd_cdb->opcode = READ_DEFECT_DATA_10;
1364 	if (arglist & CAM_ARG_FORMAT_BLOCK)
1365 		rdd_cdb->format = SRDD10_BLOCK_FORMAT;
1366 	else if (arglist & CAM_ARG_FORMAT_BFI)
1367 		rdd_cdb->format = SRDD10_BYTES_FROM_INDEX_FORMAT;
1368 	else if (arglist & CAM_ARG_FORMAT_PHYS)
1369 		rdd_cdb->format = SRDD10_PHYSICAL_SECTOR_FORMAT;
1370 	else {
1371 		error = 1;
1372 		warnx("no defect list format specified");
1373 		goto defect_bailout;
1374 	}
1375 	if (arglist & CAM_ARG_PLIST) {
1376 		rdd_cdb->format |= SRDD10_PLIST;
1377 		lists_specified++;
1378 	}
1379 
1380 	if (arglist & CAM_ARG_GLIST) {
1381 		rdd_cdb->format |= SRDD10_GLIST;
1382 		lists_specified++;
1383 	}
1384 
1385 	scsi_ulto2b(dlist_length, rdd_cdb->alloc_length);
1386 
1387 	/* Disable freezing the device queue */
1388 	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
1389 
1390 	if (cam_send_ccb(device, ccb) < 0) {
1391 		perror("error reading defect list");
1392 
1393 		if (arglist & CAM_ARG_VERBOSE) {
1394 			cam_error_print(device, ccb, CAM_ESF_ALL,
1395 					CAM_EPF_ALL, stderr);
1396 		}
1397 
1398 		error = 1;
1399 		goto defect_bailout;
1400 	}
1401 
1402 	returned_length = scsi_2btoul(((struct
1403 		scsi_read_defect_data_hdr_10 *)defect_list)->length);
1404 
1405 	returned_format = ((struct scsi_read_defect_data_hdr_10 *)
1406 			defect_list)->format;
1407 
1408 	if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR)
1409 	 && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
1410 	 && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) {
1411 		struct scsi_sense_data *sense;
1412 		int error_code, sense_key, asc, ascq;
1413 
1414 		sense = &ccb->csio.sense_data;
1415 		scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq);
1416 
1417 		/*
1418 		 * According to the SCSI spec, if the disk doesn't support
1419 		 * the requested format, it will generally return a sense
1420 		 * key of RECOVERED ERROR, and an additional sense code
1421 		 * of "DEFECT LIST NOT FOUND".  So, we check for that, and
1422 		 * also check to make sure that the returned length is
1423 		 * greater than 0, and then print out whatever format the
1424 		 * disk gave us.
1425 		 */
1426 		if ((sense_key == SSD_KEY_RECOVERED_ERROR)
1427 		 && (asc == 0x1c) && (ascq == 0x00)
1428 		 && (returned_length > 0)) {
1429 			warnx("requested defect format not available");
1430 			switch(returned_format & SRDDH10_DLIST_FORMAT_MASK) {
1431 			case SRDD10_BLOCK_FORMAT:
1432 				warnx("Device returned block format");
1433 				break;
1434 			case SRDD10_BYTES_FROM_INDEX_FORMAT:
1435 				warnx("Device returned bytes from index"
1436 				      " format");
1437 				break;
1438 			case SRDD10_PHYSICAL_SECTOR_FORMAT:
1439 				warnx("Device returned physical sector format");
1440 				break;
1441 			default:
1442 				error = 1;
1443 				warnx("Device returned unknown defect"
1444 				     " data format %#x", returned_format);
1445 				goto defect_bailout;
1446 				break; /* NOTREACHED */
1447 			}
1448 		} else {
1449 			error = 1;
1450 			warnx("Error returned from read defect data command");
1451 			if (arglist & CAM_ARG_VERBOSE)
1452 				cam_error_print(device, ccb, CAM_ESF_ALL,
1453 						CAM_EPF_ALL, stderr);
1454 			goto defect_bailout;
1455 		}
1456 	} else if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1457 		error = 1;
1458 		warnx("Error returned from read defect data command");
1459 		if (arglist & CAM_ARG_VERBOSE)
1460 			cam_error_print(device, ccb, CAM_ESF_ALL,
1461 					CAM_EPF_ALL, stderr);
1462 		goto defect_bailout;
1463 	}
1464 
1465 	/*
1466 	 * XXX KDM  I should probably clean up the printout format for the
1467 	 * disk defects.
1468 	 */
1469 	switch (returned_format & SRDDH10_DLIST_FORMAT_MASK){
1470 		case SRDDH10_PHYSICAL_SECTOR_FORMAT:
1471 		{
1472 			struct scsi_defect_desc_phys_sector *dlist;
1473 
1474 			dlist = (struct scsi_defect_desc_phys_sector *)
1475 				(defect_list +
1476 				sizeof(struct scsi_read_defect_data_hdr_10));
1477 
1478 			num_returned = returned_length /
1479 				sizeof(struct scsi_defect_desc_phys_sector);
1480 
1481 			fprintf(stderr, "Got %d defect", num_returned);
1482 
1483 			if ((lists_specified == 0) || (num_returned == 0)) {
1484 				fprintf(stderr, "s.\n");
1485 				break;
1486 			} else if (num_returned == 1)
1487 				fprintf(stderr, ":\n");
1488 			else
1489 				fprintf(stderr, "s:\n");
1490 
1491 			for (i = 0; i < num_returned; i++) {
1492 				fprintf(stdout, "%d:%d:%d\n",
1493 					scsi_3btoul(dlist[i].cylinder),
1494 					dlist[i].head,
1495 					scsi_4btoul(dlist[i].sector));
1496 			}
1497 			break;
1498 		}
1499 		case SRDDH10_BYTES_FROM_INDEX_FORMAT:
1500 		{
1501 			struct scsi_defect_desc_bytes_from_index *dlist;
1502 
1503 			dlist = (struct scsi_defect_desc_bytes_from_index *)
1504 				(defect_list +
1505 				sizeof(struct scsi_read_defect_data_hdr_10));
1506 
1507 			num_returned = returned_length /
1508 			      sizeof(struct scsi_defect_desc_bytes_from_index);
1509 
1510 			fprintf(stderr, "Got %d defect", num_returned);
1511 
1512 			if ((lists_specified == 0) || (num_returned == 0)) {
1513 				fprintf(stderr, "s.\n");
1514 				break;
1515 			} else if (num_returned == 1)
1516 				fprintf(stderr, ":\n");
1517 			else
1518 				fprintf(stderr, "s:\n");
1519 
1520 			for (i = 0; i < num_returned; i++) {
1521 				fprintf(stdout, "%d:%d:%d\n",
1522 					scsi_3btoul(dlist[i].cylinder),
1523 					dlist[i].head,
1524 					scsi_4btoul(dlist[i].bytes_from_index));
1525 			}
1526 			break;
1527 		}
1528 		case SRDDH10_BLOCK_FORMAT:
1529 		{
1530 			struct scsi_defect_desc_block *dlist;
1531 
1532 			dlist = (struct scsi_defect_desc_block *)(defect_list +
1533 				sizeof(struct scsi_read_defect_data_hdr_10));
1534 
1535 			num_returned = returned_length /
1536 			      sizeof(struct scsi_defect_desc_block);
1537 
1538 			fprintf(stderr, "Got %d defect", num_returned);
1539 
1540 			if ((lists_specified == 0) || (num_returned == 0)) {
1541 				fprintf(stderr, "s.\n");
1542 				break;
1543 			} else if (num_returned == 1)
1544 				fprintf(stderr, ":\n");
1545 			else
1546 				fprintf(stderr, "s:\n");
1547 
1548 			for (i = 0; i < num_returned; i++)
1549 				fprintf(stdout, "%u\n",
1550 					scsi_4btoul(dlist[i].address));
1551 			break;
1552 		}
1553 		default:
1554 			fprintf(stderr, "Unknown defect format %d\n",
1555 				returned_format & SRDDH10_DLIST_FORMAT_MASK);
1556 			error = 1;
1557 			break;
1558 	}
1559 defect_bailout:
1560 
1561 	if (defect_list != NULL)
1562 		free(defect_list);
1563 
1564 	if (ccb != NULL)
1565 		cam_freeccb(ccb);
1566 
1567 	return(error);
1568 }
1569 #endif /* MINIMALISTIC */
1570 
1571 #if 0
1572 void
1573 reassignblocks(struct cam_device *device, u_int32_t *blocks, int num_blocks)
1574 {
1575 	union ccb *ccb;
1576 
1577 	ccb = cam_getccb(device);
1578 
1579 	cam_freeccb(ccb);
1580 }
1581 #endif
1582 
1583 #ifndef MINIMALISTIC
1584 void
1585 mode_sense(struct cam_device *device, int mode_page, int page_control,
1586 	   int dbd, int retry_count, int timeout, u_int8_t *data, int datalen)
1587 {
1588 	union ccb *ccb;
1589 	int retval;
1590 
1591 	ccb = cam_getccb(device);
1592 
1593 	if (ccb == NULL)
1594 		errx(1, "mode_sense: couldn't allocate CCB");
1595 
1596 	bzero(&(&ccb->ccb_h)[1],
1597 	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
1598 
1599 	scsi_mode_sense(&ccb->csio,
1600 			/* retries */ retry_count,
1601 			/* cbfcnp */ NULL,
1602 			/* tag_action */ MSG_SIMPLE_Q_TAG,
1603 			/* dbd */ dbd,
1604 			/* page_code */ page_control << 6,
1605 			/* page */ mode_page,
1606 			/* param_buf */ data,
1607 			/* param_len */ datalen,
1608 			/* sense_len */ SSD_FULL_SIZE,
1609 			/* timeout */ timeout ? timeout : 5000);
1610 
1611 	if (arglist & CAM_ARG_ERR_RECOVER)
1612 		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
1613 
1614 	/* Disable freezing the device queue */
1615 	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
1616 
1617 	if (((retval = cam_send_ccb(device, ccb)) < 0)
1618 	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
1619 		if (arglist & CAM_ARG_VERBOSE) {
1620 			cam_error_print(device, ccb, CAM_ESF_ALL,
1621 					CAM_EPF_ALL, stderr);
1622 		}
1623 		cam_freeccb(ccb);
1624 		cam_close_device(device);
1625 		if (retval < 0)
1626 			err(1, "error sending mode sense command");
1627 		else
1628 			errx(1, "error sending mode sense command");
1629 	}
1630 
1631 	cam_freeccb(ccb);
1632 }
1633 
1634 void
1635 mode_select(struct cam_device *device, int save_pages, int retry_count,
1636 	   int timeout, u_int8_t *data, int datalen)
1637 {
1638 	union ccb *ccb;
1639 	int retval;
1640 
1641 	ccb = cam_getccb(device);
1642 
1643 	if (ccb == NULL)
1644 		errx(1, "mode_select: couldn't allocate CCB");
1645 
1646 	bzero(&(&ccb->ccb_h)[1],
1647 	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
1648 
1649 	scsi_mode_select(&ccb->csio,
1650 			 /* retries */ retry_count,
1651 			 /* cbfcnp */ NULL,
1652 			 /* tag_action */ MSG_SIMPLE_Q_TAG,
1653 			 /* scsi_page_fmt */ 1,
1654 			 /* save_pages */ save_pages,
1655 			 /* param_buf */ data,
1656 			 /* param_len */ datalen,
1657 			 /* sense_len */ SSD_FULL_SIZE,
1658 			 /* timeout */ timeout ? timeout : 5000);
1659 
1660 	if (arglist & CAM_ARG_ERR_RECOVER)
1661 		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
1662 
1663 	/* Disable freezing the device queue */
1664 	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
1665 
1666 	if (((retval = cam_send_ccb(device, ccb)) < 0)
1667 	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
1668 		if (arglist & CAM_ARG_VERBOSE) {
1669 			cam_error_print(device, ccb, CAM_ESF_ALL,
1670 					CAM_EPF_ALL, stderr);
1671 		}
1672 		cam_freeccb(ccb);
1673 		cam_close_device(device);
1674 
1675 		if (retval < 0)
1676 			err(1, "error sending mode select command");
1677 		else
1678 			errx(1, "error sending mode select command");
1679 
1680 	}
1681 
1682 	cam_freeccb(ccb);
1683 }
1684 
1685 void
1686 modepage(struct cam_device *device, int argc, char **argv, char *combinedopt,
1687 	 int retry_count, int timeout)
1688 {
1689 	int c, mode_page = -1, page_control = 0;
1690 	int binary = 0, list = 0;
1691 
1692 	while ((c = getopt(argc, argv, combinedopt)) != -1) {
1693 		switch(c) {
1694 		case 'b':
1695 			binary = 1;
1696 			break;
1697 		case 'd':
1698 			arglist |= CAM_ARG_DBD;
1699 			break;
1700 		case 'e':
1701 			arglist |= CAM_ARG_MODE_EDIT;
1702 			break;
1703 		case 'l':
1704 			list = 1;
1705 			break;
1706 		case 'm':
1707 			mode_page = strtol(optarg, NULL, 0);
1708 			if (mode_page < 0)
1709 				errx(1, "invalid mode page %d", mode_page);
1710 			break;
1711 		case 'P':
1712 			page_control = strtol(optarg, NULL, 0);
1713 			if ((page_control < 0) || (page_control > 3))
1714 				errx(1, "invalid page control field %d",
1715 				     page_control);
1716 			arglist |= CAM_ARG_PAGE_CNTL;
1717 			break;
1718 		default:
1719 			break;
1720 		}
1721 	}
1722 
1723 	if (mode_page == -1 && list == 0)
1724 		errx(1, "you must specify a mode page!");
1725 
1726 	if (list) {
1727 		mode_list(device, page_control, arglist & CAM_ARG_DBD,
1728 		    retry_count, timeout);
1729 	} else {
1730 		mode_edit(device, mode_page, page_control,
1731 		    arglist & CAM_ARG_DBD, arglist & CAM_ARG_MODE_EDIT, binary,
1732 		    retry_count, timeout);
1733 	}
1734 }
1735 
1736 static int
1737 scsicmd(struct cam_device *device, int argc, char **argv, char *combinedopt,
1738 	int retry_count, int timeout)
1739 {
1740 	union ccb *ccb;
1741 	u_int32_t flags = CAM_DIR_NONE;
1742 	u_int8_t *data_ptr = NULL;
1743 	u_int8_t cdb[20];
1744 	struct get_hook hook;
1745 	int c, data_bytes = 0;
1746 	int cdb_len = 0;
1747 	char *datastr = NULL, *tstr;
1748 	int error = 0;
1749 	int fd_data = 0;
1750 	int retval;
1751 
1752 	ccb = cam_getccb(device);
1753 
1754 	if (ccb == NULL) {
1755 		warnx("scsicmd: error allocating ccb");
1756 		return(1);
1757 	}
1758 
1759 	bzero(&(&ccb->ccb_h)[1],
1760 	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
1761 
1762 	while ((c = getopt(argc, argv, combinedopt)) != -1) {
1763 		switch(c) {
1764 		case 'c':
1765 			tstr = optarg;
1766 			while (isspace(*tstr) && (*tstr != '\0'))
1767 				tstr++;
1768 			hook.argc = argc - optind;
1769 			hook.argv = argv + optind;
1770 			hook.got = 0;
1771 			cdb_len = buff_encode_visit(cdb, sizeof(cdb), tstr,
1772 						    iget, &hook);
1773 			/*
1774 			 * Increment optind by the number of arguments the
1775 			 * encoding routine processed.  After each call to
1776 			 * getopt(3), optind points to the argument that
1777 			 * getopt should process _next_.  In this case,
1778 			 * that means it points to the first command string
1779 			 * argument, if there is one.  Once we increment
1780 			 * this, it should point to either the next command
1781 			 * line argument, or it should be past the end of
1782 			 * the list.
1783 			 */
1784 			optind += hook.got;
1785 			break;
1786 		case 'i':
1787 			if (arglist & CAM_ARG_CMD_OUT) {
1788 				warnx("command must either be "
1789 				      "read or write, not both");
1790 				error = 1;
1791 				goto scsicmd_bailout;
1792 			}
1793 			arglist |= CAM_ARG_CMD_IN;
1794 			flags = CAM_DIR_IN;
1795 			data_bytes = strtol(optarg, NULL, 0);
1796 			if (data_bytes <= 0) {
1797 				warnx("invalid number of input bytes %d",
1798 				      data_bytes);
1799 				error = 1;
1800 				goto scsicmd_bailout;
1801 			}
1802 			hook.argc = argc - optind;
1803 			hook.argv = argv + optind;
1804 			hook.got = 0;
1805 			optind++;
1806 			datastr = cget(&hook, NULL);
1807 			/*
1808 			 * If the user supplied "-" instead of a format, he
1809 			 * wants the data to be written to stdout.
1810 			 */
1811 			if ((datastr != NULL)
1812 			 && (datastr[0] == '-'))
1813 				fd_data = 1;
1814 
1815 			data_ptr = (u_int8_t *)malloc(data_bytes);
1816 			if (data_ptr == NULL) {
1817 				warnx("can't malloc memory for data_ptr");
1818 				error = 1;
1819 				goto scsicmd_bailout;
1820 			}
1821 			break;
1822 		case 'o':
1823 			if (arglist & CAM_ARG_CMD_IN) {
1824 				warnx("command must either be "
1825 				      "read or write, not both");
1826 				error = 1;
1827 				goto scsicmd_bailout;
1828 			}
1829 			arglist |= CAM_ARG_CMD_OUT;
1830 			flags = CAM_DIR_OUT;
1831 			data_bytes = strtol(optarg, NULL, 0);
1832 			if (data_bytes <= 0) {
1833 				warnx("invalid number of output bytes %d",
1834 				      data_bytes);
1835 				error = 1;
1836 				goto scsicmd_bailout;
1837 			}
1838 			hook.argc = argc - optind;
1839 			hook.argv = argv + optind;
1840 			hook.got = 0;
1841 			datastr = cget(&hook, NULL);
1842 			data_ptr = (u_int8_t *)malloc(data_bytes);
1843 			if (data_ptr == NULL) {
1844 				warnx("can't malloc memory for data_ptr");
1845 				error = 1;
1846 				goto scsicmd_bailout;
1847 			}
1848 			/*
1849 			 * If the user supplied "-" instead of a format, he
1850 			 * wants the data to be read from stdin.
1851 			 */
1852 			if ((datastr != NULL)
1853 			 && (datastr[0] == '-'))
1854 				fd_data = 1;
1855 			else
1856 				buff_encode_visit(data_ptr, data_bytes, datastr,
1857 						  iget, &hook);
1858 			optind += hook.got;
1859 			break;
1860 		default:
1861 			break;
1862 		}
1863 	}
1864 
1865 	/*
1866 	 * If fd_data is set, and we're writing to the device, we need to
1867 	 * read the data the user wants written from stdin.
1868 	 */
1869 	if ((fd_data == 1) && (arglist & CAM_ARG_CMD_OUT)) {
1870 		ssize_t amt_read;
1871 		int amt_to_read = data_bytes;
1872 		u_int8_t *buf_ptr = data_ptr;
1873 
1874 		for (amt_read = 0; amt_to_read > 0;
1875 		     amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) {
1876 			if (amt_read == -1) {
1877 				warn("error reading data from stdin");
1878 				error = 1;
1879 				goto scsicmd_bailout;
1880 			}
1881 			amt_to_read -= amt_read;
1882 			buf_ptr += amt_read;
1883 		}
1884 	}
1885 
1886 	if (arglist & CAM_ARG_ERR_RECOVER)
1887 		flags |= CAM_PASS_ERR_RECOVER;
1888 
1889 	/* Disable freezing the device queue */
1890 	flags |= CAM_DEV_QFRZDIS;
1891 
1892 	/*
1893 	 * This is taken from the SCSI-3 draft spec.
1894 	 * (T10/1157D revision 0.3)
1895 	 * The top 3 bits of an opcode are the group code.  The next 5 bits
1896 	 * are the command code.
1897 	 * Group 0:  six byte commands
1898 	 * Group 1:  ten byte commands
1899 	 * Group 2:  ten byte commands
1900 	 * Group 3:  reserved
1901 	 * Group 4:  sixteen byte commands
1902 	 * Group 5:  twelve byte commands
1903 	 * Group 6:  vendor specific
1904 	 * Group 7:  vendor specific
1905 	 */
1906 	switch((cdb[0] >> 5) & 0x7) {
1907 		case 0:
1908 			cdb_len = 6;
1909 			break;
1910 		case 1:
1911 		case 2:
1912 			cdb_len = 10;
1913 			break;
1914 		case 3:
1915 		case 6:
1916 		case 7:
1917 		        /* computed by buff_encode_visit */
1918 			break;
1919 		case 4:
1920 			cdb_len = 16;
1921 			break;
1922 		case 5:
1923 			cdb_len = 12;
1924 			break;
1925 	}
1926 
1927 	/*
1928 	 * We should probably use csio_build_visit or something like that
1929 	 * here, but it's easier to encode arguments as you go.  The
1930 	 * alternative would be skipping the CDB argument and then encoding
1931 	 * it here, since we've got the data buffer argument by now.
1932 	 */
1933 	bcopy(cdb, &ccb->csio.cdb_io.cdb_bytes, cdb_len);
1934 
1935 	cam_fill_csio(&ccb->csio,
1936 		      /*retries*/ retry_count,
1937 		      /*cbfcnp*/ NULL,
1938 		      /*flags*/ flags,
1939 		      /*tag_action*/ MSG_SIMPLE_Q_TAG,
1940 		      /*data_ptr*/ data_ptr,
1941 		      /*dxfer_len*/ data_bytes,
1942 		      /*sense_len*/ SSD_FULL_SIZE,
1943 		      /*cdb_len*/ cdb_len,
1944 		      /*timeout*/ timeout ? timeout : 5000);
1945 
1946 	if (((retval = cam_send_ccb(device, ccb)) < 0)
1947 	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
1948 		if (retval < 0)
1949 			warn("error sending command");
1950 		else
1951 			warnx("error sending command");
1952 
1953 		if (arglist & CAM_ARG_VERBOSE) {
1954 			cam_error_print(device, ccb, CAM_ESF_ALL,
1955 					CAM_EPF_ALL, stderr);
1956 		}
1957 
1958 		error = 1;
1959 		goto scsicmd_bailout;
1960 	}
1961 
1962 
1963 	if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
1964 	 && (arglist & CAM_ARG_CMD_IN)
1965 	 && (data_bytes > 0)) {
1966 		if (fd_data == 0) {
1967 			buff_decode_visit(data_ptr, data_bytes, datastr,
1968 					  arg_put, NULL);
1969 			fprintf(stdout, "\n");
1970 		} else {
1971 			ssize_t amt_written;
1972 			int amt_to_write = data_bytes;
1973 			u_int8_t *buf_ptr = data_ptr;
1974 
1975 			for (amt_written = 0; (amt_to_write > 0) &&
1976 			     (amt_written =write(1, buf_ptr,amt_to_write))> 0;){
1977 				amt_to_write -= amt_written;
1978 				buf_ptr += amt_written;
1979 			}
1980 			if (amt_written == -1) {
1981 				warn("error writing data to stdout");
1982 				error = 1;
1983 				goto scsicmd_bailout;
1984 			} else if ((amt_written == 0)
1985 				&& (amt_to_write > 0)) {
1986 				warnx("only wrote %u bytes out of %u",
1987 				      data_bytes - amt_to_write, data_bytes);
1988 			}
1989 		}
1990 	}
1991 
1992 scsicmd_bailout:
1993 
1994 	if ((data_bytes > 0) && (data_ptr != NULL))
1995 		free(data_ptr);
1996 
1997 	cam_freeccb(ccb);
1998 
1999 	return(error);
2000 }
2001 
2002 static int
2003 camdebug(int argc, char **argv, char *combinedopt)
2004 {
2005 	int c, fd;
2006 	int mybus = -1, mytarget = -1, mylun = -1;
2007 	char *tstr, *tmpstr = NULL;
2008 	union ccb ccb;
2009 	int error = 0;
2010 
2011 	bzero(&ccb, sizeof(union ccb));
2012 
2013 	while ((c = getopt(argc, argv, combinedopt)) != -1) {
2014 		switch(c) {
2015 		case 'I':
2016 			arglist |= CAM_ARG_DEBUG_INFO;
2017 			ccb.cdbg.flags |= CAM_DEBUG_INFO;
2018 			break;
2019 		case 'P':
2020 			arglist |= CAM_ARG_DEBUG_PERIPH;
2021 			ccb.cdbg.flags |= CAM_DEBUG_PERIPH;
2022 			break;
2023 		case 'S':
2024 			arglist |= CAM_ARG_DEBUG_SUBTRACE;
2025 			ccb.cdbg.flags |= CAM_DEBUG_SUBTRACE;
2026 			break;
2027 		case 'T':
2028 			arglist |= CAM_ARG_DEBUG_TRACE;
2029 			ccb.cdbg.flags |= CAM_DEBUG_TRACE;
2030 			break;
2031 		case 'X':
2032 			arglist |= CAM_ARG_DEBUG_XPT;
2033 			ccb.cdbg.flags |= CAM_DEBUG_XPT;
2034 			break;
2035 		case 'c':
2036 			arglist |= CAM_ARG_DEBUG_CDB;
2037 			ccb.cdbg.flags |= CAM_DEBUG_CDB;
2038 			break;
2039 		default:
2040 			break;
2041 		}
2042 	}
2043 
2044 	if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
2045 		warnx("error opening transport layer device %s", XPT_DEVICE);
2046 		warn("%s", XPT_DEVICE);
2047 		return(1);
2048 	}
2049 	argc -= optind;
2050 	argv += optind;
2051 
2052 	if (argc <= 0) {
2053 		warnx("you must specify \"off\", \"all\" or a bus,");
2054 		warnx("bus:target, or bus:target:lun");
2055 		close(fd);
2056 		return(1);
2057 	}
2058 
2059 	tstr = *argv;
2060 
2061 	while (isspace(*tstr) && (*tstr != '\0'))
2062 		tstr++;
2063 
2064 	if (strncmp(tstr, "off", 3) == 0) {
2065 		ccb.cdbg.flags = CAM_DEBUG_NONE;
2066 		arglist &= ~(CAM_ARG_DEBUG_INFO|CAM_ARG_DEBUG_PERIPH|
2067 			     CAM_ARG_DEBUG_TRACE|CAM_ARG_DEBUG_SUBTRACE|
2068 			     CAM_ARG_DEBUG_XPT);
2069 	} else if (strncmp(tstr, "all", 3) != 0) {
2070 		tmpstr = (char *)strtok(tstr, ":");
2071 		if ((tmpstr != NULL) && (*tmpstr != '\0')){
2072 			mybus = strtol(tmpstr, NULL, 0);
2073 			arglist |= CAM_ARG_BUS;
2074 			tmpstr = (char *)strtok(NULL, ":");
2075 			if ((tmpstr != NULL) && (*tmpstr != '\0')){
2076 				mytarget = strtol(tmpstr, NULL, 0);
2077 				arglist |= CAM_ARG_TARGET;
2078 				tmpstr = (char *)strtok(NULL, ":");
2079 				if ((tmpstr != NULL) && (*tmpstr != '\0')){
2080 					mylun = strtol(tmpstr, NULL, 0);
2081 					arglist |= CAM_ARG_LUN;
2082 				}
2083 			}
2084 		} else {
2085 			error = 1;
2086 			warnx("you must specify \"all\", \"off\", or a bus,");
2087 			warnx("bus:target, or bus:target:lun to debug");
2088 		}
2089 	}
2090 
2091 	if (error == 0) {
2092 
2093 		ccb.ccb_h.func_code = XPT_DEBUG;
2094 		ccb.ccb_h.path_id = mybus;
2095 		ccb.ccb_h.target_id = mytarget;
2096 		ccb.ccb_h.target_lun = mylun;
2097 
2098 		if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
2099 			warn("CAMIOCOMMAND ioctl failed");
2100 			error = 1;
2101 		}
2102 
2103 		if (error == 0) {
2104 			if ((ccb.ccb_h.status & CAM_STATUS_MASK) ==
2105 			     CAM_FUNC_NOTAVAIL) {
2106 				warnx("CAM debugging not available");
2107 				warnx("you need to put options CAMDEBUG in"
2108 				      " your kernel config file!");
2109 				error = 1;
2110 			} else if ((ccb.ccb_h.status & CAM_STATUS_MASK) !=
2111 				    CAM_REQ_CMP) {
2112 				warnx("XPT_DEBUG CCB failed with status %#x",
2113 				      ccb.ccb_h.status);
2114 				error = 1;
2115 			} else {
2116 				if (ccb.cdbg.flags == CAM_DEBUG_NONE) {
2117 					fprintf(stderr,
2118 						"Debugging turned off\n");
2119 				} else {
2120 					fprintf(stderr,
2121 						"Debugging enabled for "
2122 						"%d:%d:%d\n",
2123 						mybus, mytarget, mylun);
2124 				}
2125 			}
2126 		}
2127 		close(fd);
2128 	}
2129 
2130 	return(error);
2131 }
2132 
2133 static int
2134 tagcontrol(struct cam_device *device, int argc, char **argv,
2135 	   char *combinedopt)
2136 {
2137 	int c;
2138 	union ccb *ccb;
2139 	int numtags = -1;
2140 	int retval = 0;
2141 	int quiet = 0;
2142 	char pathstr[1024];
2143 
2144 	ccb = cam_getccb(device);
2145 
2146 	if (ccb == NULL) {
2147 		warnx("tagcontrol: error allocating ccb");
2148 		return(1);
2149 	}
2150 
2151 	while ((c = getopt(argc, argv, combinedopt)) != -1) {
2152 		switch(c) {
2153 		case 'N':
2154 			numtags = strtol(optarg, NULL, 0);
2155 			if (numtags < 0) {
2156 				warnx("tag count %d is < 0", numtags);
2157 				retval = 1;
2158 				goto tagcontrol_bailout;
2159 			}
2160 			break;
2161 		case 'q':
2162 			quiet++;
2163 			break;
2164 		default:
2165 			break;
2166 		}
2167 	}
2168 
2169 	cam_path_string(device, pathstr, sizeof(pathstr));
2170 
2171 	if (numtags >= 0) {
2172 		bzero(&(&ccb->ccb_h)[1],
2173 		      sizeof(struct ccb_relsim) - sizeof(struct ccb_hdr));
2174 		ccb->ccb_h.func_code = XPT_REL_SIMQ;
2175 		ccb->crs.release_flags = RELSIM_ADJUST_OPENINGS;
2176 		ccb->crs.openings = numtags;
2177 
2178 
2179 		if (cam_send_ccb(device, ccb) < 0) {
2180 			perror("error sending XPT_REL_SIMQ CCB");
2181 			retval = 1;
2182 			goto tagcontrol_bailout;
2183 		}
2184 
2185 		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2186 			warnx("XPT_REL_SIMQ CCB failed");
2187 			cam_error_print(device, ccb, CAM_ESF_ALL,
2188 					CAM_EPF_ALL, stderr);
2189 			retval = 1;
2190 			goto tagcontrol_bailout;
2191 		}
2192 
2193 
2194 		if (quiet == 0)
2195 			fprintf(stdout, "%stagged openings now %d\n",
2196 				pathstr, ccb->crs.openings);
2197 	}
2198 
2199 	bzero(&(&ccb->ccb_h)[1],
2200 	      sizeof(struct ccb_getdevstats) - sizeof(struct ccb_hdr));
2201 
2202 	ccb->ccb_h.func_code = XPT_GDEV_STATS;
2203 
2204 	if (cam_send_ccb(device, ccb) < 0) {
2205 		perror("error sending XPT_GDEV_STATS CCB");
2206 		retval = 1;
2207 		goto tagcontrol_bailout;
2208 	}
2209 
2210 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2211 		warnx("XPT_GDEV_STATS CCB failed");
2212 		cam_error_print(device, ccb, CAM_ESF_ALL,
2213 				CAM_EPF_ALL, stderr);
2214 		retval = 1;
2215 		goto tagcontrol_bailout;
2216 	}
2217 
2218 	if (arglist & CAM_ARG_VERBOSE) {
2219 		fprintf(stdout, "%s", pathstr);
2220 		fprintf(stdout, "dev_openings  %d\n", ccb->cgds.dev_openings);
2221 		fprintf(stdout, "%s", pathstr);
2222 		fprintf(stdout, "dev_active    %d\n", ccb->cgds.dev_active);
2223 		fprintf(stdout, "%s", pathstr);
2224 		fprintf(stdout, "devq_openings %d\n", ccb->cgds.devq_openings);
2225 		fprintf(stdout, "%s", pathstr);
2226 		fprintf(stdout, "devq_queued   %d\n", ccb->cgds.devq_queued);
2227 		fprintf(stdout, "%s", pathstr);
2228 		fprintf(stdout, "held          %d\n", ccb->cgds.held);
2229 		fprintf(stdout, "%s", pathstr);
2230 		fprintf(stdout, "mintags       %d\n", ccb->cgds.mintags);
2231 		fprintf(stdout, "%s", pathstr);
2232 		fprintf(stdout, "maxtags       %d\n", ccb->cgds.maxtags);
2233 	} else {
2234 		if (quiet == 0) {
2235 			fprintf(stdout, "%s", pathstr);
2236 			fprintf(stdout, "device openings: ");
2237 		}
2238 		fprintf(stdout, "%d\n", ccb->cgds.dev_openings +
2239 			ccb->cgds.dev_active);
2240 	}
2241 
2242 tagcontrol_bailout:
2243 
2244 	cam_freeccb(ccb);
2245 	return(retval);
2246 }
2247 
2248 static void
2249 cts_print(struct cam_device *device, struct ccb_trans_settings *cts)
2250 {
2251 	char pathstr[1024];
2252 
2253 	cam_path_string(device, pathstr, sizeof(pathstr));
2254 
2255 	if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) {
2256 
2257 		fprintf(stdout, "%ssync parameter: %d\n", pathstr,
2258 			cts->sync_period);
2259 
2260 		if (cts->sync_offset != 0) {
2261 			u_int freq;
2262 
2263 			freq = scsi_calc_syncsrate(cts->sync_period);
2264 			fprintf(stdout, "%sfrequency: %d.%03dMHz\n", pathstr,
2265 				freq / 1000, freq % 1000);
2266 		}
2267 	}
2268 
2269 	if (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID)
2270 		fprintf(stdout, "%soffset: %d\n", pathstr, cts->sync_offset);
2271 
2272 	if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID)
2273 		fprintf(stdout, "%sbus width: %d bits\n", pathstr,
2274 			(0x01 << cts->bus_width) * 8);
2275 
2276 	if (cts->valid & CCB_TRANS_DISC_VALID)
2277 		fprintf(stdout, "%sdisconnection is %s\n", pathstr,
2278 			(cts->flags & CCB_TRANS_DISC_ENB) ? "enabled" :
2279 			"disabled");
2280 
2281 	if (cts->valid & CCB_TRANS_TQ_VALID)
2282 		fprintf(stdout, "%stagged queueing is %s\n", pathstr,
2283 			(cts->flags & CCB_TRANS_TAG_ENB) ? "enabled" :
2284 			"disabled");
2285 
2286 }
2287 
2288 /*
2289  * Get a path inquiry CCB for the specified device.
2290  */
2291 static int
2292 get_cpi(struct cam_device *device, struct ccb_pathinq *cpi)
2293 {
2294 	union ccb *ccb;
2295 	int retval = 0;
2296 
2297 	ccb = cam_getccb(device);
2298 
2299 	if (ccb == NULL) {
2300 		warnx("get_cpi: couldn't allocate CCB");
2301 		return(1);
2302 	}
2303 
2304 	bzero(&(&ccb->ccb_h)[1],
2305 	      sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr));
2306 
2307 	ccb->ccb_h.func_code = XPT_PATH_INQ;
2308 
2309 	if (cam_send_ccb(device, ccb) < 0) {
2310 		warn("get_cpi: error sending Path Inquiry CCB");
2311 
2312 		if (arglist & CAM_ARG_VERBOSE)
2313 			cam_error_print(device, ccb, CAM_ESF_ALL,
2314 					CAM_EPF_ALL, stderr);
2315 
2316 		retval = 1;
2317 
2318 		goto get_cpi_bailout;
2319 	}
2320 
2321 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2322 
2323 		if (arglist & CAM_ARG_VERBOSE)
2324 			cam_error_print(device, ccb, CAM_ESF_ALL,
2325 					CAM_EPF_ALL, stderr);
2326 
2327 		retval = 1;
2328 
2329 		goto get_cpi_bailout;
2330 	}
2331 
2332 	bcopy(&ccb->cpi, cpi, sizeof(struct ccb_pathinq));
2333 
2334 get_cpi_bailout:
2335 
2336 	cam_freeccb(ccb);
2337 
2338 	return(retval);
2339 }
2340 
2341 static void
2342 cpi_print(struct ccb_pathinq *cpi)
2343 {
2344 	char adapter_str[1024];
2345 	int i;
2346 
2347 	snprintf(adapter_str, sizeof(adapter_str),
2348 		 "%s%d:", cpi->dev_name, cpi->unit_number);
2349 
2350 	fprintf(stdout, "%s SIM/HBA version: %d\n", adapter_str,
2351 		cpi->version_num);
2352 
2353 	for (i = 1; i < 0xff; i = i << 1) {
2354 		const char *str;
2355 
2356 		if ((i & cpi->hba_inquiry) == 0)
2357 			continue;
2358 
2359 		fprintf(stdout, "%s supports ", adapter_str);
2360 
2361 		switch(i) {
2362 		case PI_MDP_ABLE:
2363 			str = "MDP message";
2364 			break;
2365 		case PI_WIDE_32:
2366 			str = "32 bit wide SCSI";
2367 			break;
2368 		case PI_WIDE_16:
2369 			str = "16 bit wide SCSI";
2370 			break;
2371 		case PI_SDTR_ABLE:
2372 			str = "SDTR message";
2373 			break;
2374 		case PI_LINKED_CDB:
2375 			str = "linked CDBs";
2376 			break;
2377 		case PI_TAG_ABLE:
2378 			str = "tag queue messages";
2379 			break;
2380 		case PI_SOFT_RST:
2381 			str = "soft reset alternative";
2382 			break;
2383 		default:
2384 			str = "unknown PI bit set";
2385 			break;
2386 		}
2387 		fprintf(stdout, "%s\n", str);
2388 	}
2389 
2390 	for (i = 1; i < 0xff; i = i << 1) {
2391 		const char *str;
2392 
2393 		if ((i & cpi->hba_misc) == 0)
2394 			continue;
2395 
2396 		fprintf(stdout, "%s ", adapter_str);
2397 
2398 		switch(i) {
2399 		case PIM_SCANHILO:
2400 			str = "bus scans from high ID to low ID";
2401 			break;
2402 		case PIM_NOREMOVE:
2403 			str = "removable devices not included in scan";
2404 			break;
2405 		case PIM_NOINITIATOR:
2406 			str = "initiator role not supported";
2407 			break;
2408 		case PIM_NOBUSRESET:
2409 			str = "user has disabled initial BUS RESET or"
2410 			      " controller is in target/mixed mode";
2411 			break;
2412 		default:
2413 			str = "unknown PIM bit set";
2414 			break;
2415 		}
2416 		fprintf(stdout, "%s\n", str);
2417 	}
2418 
2419 	for (i = 1; i < 0xff; i = i << 1) {
2420 		const char *str;
2421 
2422 		if ((i & cpi->target_sprt) == 0)
2423 			continue;
2424 
2425 		fprintf(stdout, "%s supports ", adapter_str);
2426 		switch(i) {
2427 		case PIT_PROCESSOR:
2428 			str = "target mode processor mode";
2429 			break;
2430 		case PIT_PHASE:
2431 			str = "target mode phase cog. mode";
2432 			break;
2433 		case PIT_DISCONNECT:
2434 			str = "disconnects in target mode";
2435 			break;
2436 		case PIT_TERM_IO:
2437 			str = "terminate I/O message in target mode";
2438 			break;
2439 		case PIT_GRP_6:
2440 			str = "group 6 commands in target mode";
2441 			break;
2442 		case PIT_GRP_7:
2443 			str = "group 7 commands in target mode";
2444 			break;
2445 		default:
2446 			str = "unknown PIT bit set";
2447 			break;
2448 		}
2449 
2450 		fprintf(stdout, "%s\n", str);
2451 	}
2452 	fprintf(stdout, "%s HBA engine count: %d\n", adapter_str,
2453 		cpi->hba_eng_cnt);
2454 	fprintf(stdout, "%s maximum target: %d\n", adapter_str,
2455 		cpi->max_target);
2456 	fprintf(stdout, "%s maximum LUN: %d\n", adapter_str,
2457 		cpi->max_lun);
2458 	fprintf(stdout, "%s highest path ID in subsystem: %d\n",
2459 		adapter_str, cpi->hpath_id);
2460 	fprintf(stdout, "%s initiator ID: %d\n", adapter_str,
2461 		cpi->initiator_id);
2462 	fprintf(stdout, "%s SIM vendor: %s\n", adapter_str, cpi->sim_vid);
2463 	fprintf(stdout, "%s HBA vendor: %s\n", adapter_str, cpi->hba_vid);
2464 	fprintf(stdout, "%s bus ID: %d\n", adapter_str, cpi->bus_id);
2465 	fprintf(stdout, "%s base transfer speed: ", adapter_str);
2466 	if (cpi->base_transfer_speed > 1000)
2467 		fprintf(stdout, "%d.%03dMB/sec\n",
2468 			cpi->base_transfer_speed / 1000,
2469 			cpi->base_transfer_speed % 1000);
2470 	else
2471 		fprintf(stdout, "%dKB/sec\n",
2472 			(cpi->base_transfer_speed % 1000) * 1000);
2473 }
2474 
2475 static int
2476 get_print_cts(struct cam_device *device, int user_settings, int quiet,
2477 	      struct ccb_trans_settings *cts)
2478 {
2479 	int retval;
2480 	union ccb *ccb;
2481 
2482 	retval = 0;
2483 	ccb = cam_getccb(device);
2484 
2485 	if (ccb == NULL) {
2486 		warnx("get_print_cts: error allocating ccb");
2487 		return(1);
2488 	}
2489 
2490 	bzero(&(&ccb->ccb_h)[1],
2491 	      sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr));
2492 
2493 	ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
2494 
2495 	if (user_settings == 0)
2496 		ccb->cts.flags = CCB_TRANS_CURRENT_SETTINGS;
2497 	else
2498 		ccb->cts.flags = CCB_TRANS_USER_SETTINGS;
2499 
2500 	if (cam_send_ccb(device, ccb) < 0) {
2501 		perror("error sending XPT_GET_TRAN_SETTINGS CCB");
2502 		if (arglist & CAM_ARG_VERBOSE)
2503 			cam_error_print(device, ccb, CAM_ESF_ALL,
2504 					CAM_EPF_ALL, stderr);
2505 		retval = 1;
2506 		goto get_print_cts_bailout;
2507 	}
2508 
2509 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2510 		warnx("XPT_GET_TRANS_SETTINGS CCB failed");
2511 		if (arglist & CAM_ARG_VERBOSE)
2512 			cam_error_print(device, ccb, CAM_ESF_ALL,
2513 					CAM_EPF_ALL, stderr);
2514 		retval = 1;
2515 		goto get_print_cts_bailout;
2516 	}
2517 
2518 	if (quiet == 0)
2519 		cts_print(device, &ccb->cts);
2520 
2521 	if (cts != NULL)
2522 		bcopy(&ccb->cts, cts, sizeof(struct ccb_trans_settings));
2523 
2524 get_print_cts_bailout:
2525 
2526 	cam_freeccb(ccb);
2527 
2528 	return(retval);
2529 }
2530 
2531 static int
2532 ratecontrol(struct cam_device *device, int retry_count, int timeout,
2533 	    int argc, char **argv, char *combinedopt)
2534 {
2535 	int c;
2536 	union ccb *ccb;
2537 	int user_settings = 0;
2538 	int retval = 0;
2539 	int disc_enable = -1, tag_enable = -1;
2540 	int offset = -1;
2541 	double syncrate = -1;
2542 	int bus_width = -1;
2543 	int quiet = 0;
2544 	int change_settings = 0, send_tur = 0;
2545 	struct ccb_pathinq cpi;
2546 
2547 	ccb = cam_getccb(device);
2548 
2549 	if (ccb == NULL) {
2550 		warnx("ratecontrol: error allocating ccb");
2551 		return(1);
2552 	}
2553 
2554 	while ((c = getopt(argc, argv, combinedopt)) != -1) {
2555 		switch(c){
2556 		case 'a':
2557 			send_tur = 1;
2558 			break;
2559 		case 'c':
2560 			user_settings = 0;
2561 			break;
2562 		case 'D':
2563 			if (strncasecmp(optarg, "enable", 6) == 0)
2564 				disc_enable = 1;
2565 			else if (strncasecmp(optarg, "disable", 7) == 0)
2566 				disc_enable = 0;
2567 			else {
2568 				warnx("-D argument \"%s\" is unknown", optarg);
2569 				retval = 1;
2570 				goto ratecontrol_bailout;
2571 			}
2572 			change_settings = 1;
2573 			break;
2574 		case 'O':
2575 			offset = strtol(optarg, NULL, 0);
2576 			if (offset < 0) {
2577 				warnx("offset value %d is < 0", offset);
2578 				retval = 1;
2579 				goto ratecontrol_bailout;
2580 			}
2581 			change_settings = 1;
2582 			break;
2583 		case 'q':
2584 			quiet++;
2585 			break;
2586 		case 'R':
2587 			syncrate = atof(optarg);
2588 
2589 			if (syncrate < 0) {
2590 				warnx("sync rate %f is < 0", syncrate);
2591 				retval = 1;
2592 				goto ratecontrol_bailout;
2593 			}
2594 			change_settings = 1;
2595 			break;
2596 		case 'T':
2597 			if (strncasecmp(optarg, "enable", 6) == 0)
2598 				tag_enable = 1;
2599 			else if (strncasecmp(optarg, "disable", 7) == 0)
2600 				tag_enable = 0;
2601 			else {
2602 				warnx("-T argument \"%s\" is unknown", optarg);
2603 				retval = 1;
2604 				goto ratecontrol_bailout;
2605 			}
2606 			change_settings = 1;
2607 			break;
2608 		case 'U':
2609 			user_settings = 1;
2610 			break;
2611 		case 'W':
2612 			bus_width = strtol(optarg, NULL, 0);
2613 			if (bus_width < 0) {
2614 				warnx("bus width %d is < 0", bus_width);
2615 				retval = 1;
2616 				goto ratecontrol_bailout;
2617 			}
2618 			change_settings = 1;
2619 			break;
2620 		default:
2621 			break;
2622 		}
2623 	}
2624 
2625 	bzero(&(&ccb->ccb_h)[1],
2626 	      sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr));
2627 
2628 	/*
2629 	 * Grab path inquiry information, so we can determine whether
2630 	 * or not the initiator is capable of the things that the user
2631 	 * requests.
2632 	 */
2633 	ccb->ccb_h.func_code = XPT_PATH_INQ;
2634 
2635 	if (cam_send_ccb(device, ccb) < 0) {
2636 		perror("error sending XPT_PATH_INQ CCB");
2637 		if (arglist & CAM_ARG_VERBOSE) {
2638 			cam_error_print(device, ccb, CAM_ESF_ALL,
2639 					CAM_EPF_ALL, stderr);
2640 		}
2641 		retval = 1;
2642 		goto ratecontrol_bailout;
2643 	}
2644 
2645 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2646 		warnx("XPT_PATH_INQ CCB failed");
2647 		if (arglist & CAM_ARG_VERBOSE) {
2648 			cam_error_print(device, ccb, CAM_ESF_ALL,
2649 					CAM_EPF_ALL, stderr);
2650 		}
2651 		retval = 1;
2652 		goto ratecontrol_bailout;
2653 	}
2654 
2655 	bcopy(&ccb->cpi, &cpi, sizeof(struct ccb_pathinq));
2656 
2657 	bzero(&(&ccb->ccb_h)[1],
2658 	      sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr));
2659 
2660 	if (quiet == 0)
2661 		fprintf(stdout, "Current Parameters:\n");
2662 
2663 	retval = get_print_cts(device, user_settings, quiet, &ccb->cts);
2664 
2665 	if (retval != 0)
2666 		goto ratecontrol_bailout;
2667 
2668 	if (arglist & CAM_ARG_VERBOSE)
2669 		cpi_print(&cpi);
2670 
2671 	if (change_settings) {
2672 		if (disc_enable != -1) {
2673 			ccb->cts.valid |= CCB_TRANS_DISC_VALID;
2674 			if (disc_enable == 0)
2675 				ccb->cts.flags &= ~CCB_TRANS_DISC_ENB;
2676 			else
2677 				ccb->cts.flags |= CCB_TRANS_DISC_ENB;
2678 		} else
2679 			ccb->cts.valid &= ~CCB_TRANS_DISC_VALID;
2680 
2681 		if (tag_enable != -1) {
2682 			if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0) {
2683 				warnx("HBA does not support tagged queueing, "
2684 				      "so you cannot modify tag settings");
2685 				retval = 1;
2686 				goto ratecontrol_bailout;
2687 			}
2688 
2689 			ccb->cts.valid |= CCB_TRANS_TQ_VALID;
2690 
2691 			if (tag_enable == 0)
2692 				ccb->cts.flags &= ~CCB_TRANS_TAG_ENB;
2693 			else
2694 				ccb->cts.flags |= CCB_TRANS_TAG_ENB;
2695 		} else
2696 			ccb->cts.valid &= ~CCB_TRANS_TQ_VALID;
2697 
2698 		if (offset != -1) {
2699 			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
2700 				warnx("HBA at %s%d is not cable of changing "
2701 				      "offset", cpi.dev_name,
2702 				      cpi.unit_number);
2703 				retval = 1;
2704 				goto ratecontrol_bailout;
2705 			}
2706 			ccb->cts.valid |= CCB_TRANS_SYNC_OFFSET_VALID;
2707 			ccb->cts.sync_offset = offset;
2708 		} else
2709 			ccb->cts.valid &= ~CCB_TRANS_SYNC_OFFSET_VALID;
2710 
2711 		if (syncrate != -1) {
2712 			int prelim_sync_period;
2713 			u_int freq;
2714 
2715 			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
2716 				warnx("HBA at %s%d is not cable of changing "
2717 				      "transfer rates", cpi.dev_name,
2718 				      cpi.unit_number);
2719 				retval = 1;
2720 				goto ratecontrol_bailout;
2721 			}
2722 
2723 			ccb->cts.valid |= CCB_TRANS_SYNC_RATE_VALID;
2724 
2725 			/*
2726 			 * The sync rate the user gives us is in MHz.
2727 			 * We need to translate it into KHz for this
2728 			 * calculation.
2729 			 */
2730 			syncrate *= 1000;
2731 
2732 			/*
2733 			 * Next, we calculate a "preliminary" sync period
2734 			 * in tenths of a nanosecond.
2735 			 */
2736 			if (syncrate == 0)
2737 				prelim_sync_period = 0;
2738 			else
2739 				prelim_sync_period = 10000000 / syncrate;
2740 
2741 			ccb->cts.sync_period =
2742 				scsi_calc_syncparam(prelim_sync_period);
2743 
2744 			freq = scsi_calc_syncsrate(ccb->cts.sync_period);
2745 		} else
2746 			ccb->cts.valid &= ~CCB_TRANS_SYNC_RATE_VALID;
2747 
2748 		/*
2749 		 * The bus_width argument goes like this:
2750 		 * 0 == 8 bit
2751 		 * 1 == 16 bit
2752 		 * 2 == 32 bit
2753 		 * Therefore, if you shift the number of bits given on the
2754 		 * command line right by 4, you should get the correct
2755 		 * number.
2756 		 */
2757 		if (bus_width != -1) {
2758 
2759 			/*
2760 			 * We might as well validate things here with a
2761 			 * decipherable error message, rather than what
2762 			 * will probably be an indecipherable error message
2763 			 * by the time it gets back to us.
2764 			 */
2765 			if ((bus_width == 16)
2766 			 && ((cpi.hba_inquiry & PI_WIDE_16) == 0)) {
2767 				warnx("HBA does not support 16 bit bus width");
2768 				retval = 1;
2769 				goto ratecontrol_bailout;
2770 			} else if ((bus_width == 32)
2771 				&& ((cpi.hba_inquiry & PI_WIDE_32) == 0)) {
2772 				warnx("HBA does not support 32 bit bus width");
2773 				retval = 1;
2774 				goto ratecontrol_bailout;
2775 			} else if ((bus_width != 8)
2776 				&& (bus_width != 16)
2777 				&& (bus_width != 32)) {
2778 				warnx("Invalid bus width %d", bus_width);
2779 				retval = 1;
2780 				goto ratecontrol_bailout;
2781 			}
2782 
2783 			ccb->cts.valid |= CCB_TRANS_BUS_WIDTH_VALID;
2784 			ccb->cts.bus_width = bus_width >> 4;
2785 		} else
2786 			ccb->cts.valid &= ~CCB_TRANS_BUS_WIDTH_VALID;
2787 
2788 		ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
2789 
2790 		if (cam_send_ccb(device, ccb) < 0) {
2791 			perror("error sending XPT_SET_TRAN_SETTINGS CCB");
2792 			if (arglist & CAM_ARG_VERBOSE) {
2793 				cam_error_print(device, ccb, CAM_ESF_ALL,
2794 						CAM_EPF_ALL, stderr);
2795 			}
2796 			retval = 1;
2797 			goto ratecontrol_bailout;
2798 		}
2799 
2800 		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2801 			warnx("XPT_SET_TRANS_SETTINGS CCB failed");
2802 			if (arglist & CAM_ARG_VERBOSE) {
2803 				cam_error_print(device, ccb, CAM_ESF_ALL,
2804 						CAM_EPF_ALL, stderr);
2805 			}
2806 			retval = 1;
2807 			goto ratecontrol_bailout;
2808 		}
2809 	}
2810 
2811 	if (send_tur) {
2812 		retval = testunitready(device, retry_count, timeout,
2813 				       (arglist & CAM_ARG_VERBOSE) ? 0 : 1);
2814 
2815 		/*
2816 		 * If the TUR didn't succeed, just bail.
2817 		 */
2818 		if (retval != 0) {
2819 			if (quiet == 0)
2820 				fprintf(stderr, "Test Unit Ready failed\n");
2821 			goto ratecontrol_bailout;
2822 		}
2823 
2824 		/*
2825 		 * If the user wants things quiet, there's no sense in
2826 		 * getting the transfer settings, if we're not going
2827 		 * to print them.
2828 		 */
2829 		if (quiet != 0)
2830 			goto ratecontrol_bailout;
2831 
2832 		fprintf(stdout, "New Parameters:\n");
2833 		retval = get_print_cts(device, user_settings, 0, NULL);
2834 	}
2835 
2836 ratecontrol_bailout:
2837 
2838 	cam_freeccb(ccb);
2839 	return(retval);
2840 }
2841 
2842 static int
2843 scsiformat(struct cam_device *device, int argc, char **argv,
2844 	   char *combinedopt, int retry_count, int timeout)
2845 {
2846 	union ccb *ccb;
2847 	int c;
2848 	int ycount = 0, quiet = 0;
2849 	int error = 0, response = 0, retval = 0;
2850 	int use_timeout = 10800 * 1000;
2851 	int immediate = 1;
2852 	struct format_defect_list_header fh;
2853 	u_int8_t *data_ptr = NULL;
2854 	u_int32_t dxfer_len = 0;
2855 	u_int8_t byte2 = 0;
2856 	int num_warnings = 0;
2857 	int reportonly = 0;
2858 
2859 	ccb = cam_getccb(device);
2860 
2861 	if (ccb == NULL) {
2862 		warnx("scsiformat: error allocating ccb");
2863 		return(1);
2864 	}
2865 
2866 	bzero(&(&ccb->ccb_h)[1],
2867 	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
2868 
2869 	while ((c = getopt(argc, argv, combinedopt)) != -1) {
2870 		switch(c) {
2871 		case 'q':
2872 			quiet++;
2873 			break;
2874 		case 'r':
2875 			reportonly = 1;
2876 			break;
2877 		case 'w':
2878 			immediate = 0;
2879 			break;
2880 		case 'y':
2881 			ycount++;
2882 			break;
2883 		}
2884 	}
2885 
2886 	if (reportonly)
2887 		goto doreport;
2888 
2889 	if (quiet == 0) {
2890 		fprintf(stdout, "You are about to REMOVE ALL DATA from the "
2891 			"following device:\n");
2892 
2893 		error = scsidoinquiry(device, argc, argv, combinedopt,
2894 				      retry_count, timeout);
2895 
2896 		if (error != 0) {
2897 			warnx("scsiformat: error sending inquiry");
2898 			goto scsiformat_bailout;
2899 		}
2900 	}
2901 
2902 	if (ycount == 0) {
2903 
2904 		do {
2905 			char str[1024];
2906 
2907 			fprintf(stdout, "Are you SURE you want to do "
2908 				"this? (yes/no) ");
2909 
2910 			if (fgets(str, sizeof(str), stdin) != NULL) {
2911 
2912 				if (strncasecmp(str, "yes", 3) == 0)
2913 					response = 1;
2914 				else if (strncasecmp(str, "no", 2) == 0)
2915 					response = -1;
2916 				else {
2917 					fprintf(stdout, "Please answer"
2918 						" \"yes\" or \"no\"\n");
2919 				}
2920 			}
2921 		} while (response == 0);
2922 
2923 		if (response == -1) {
2924 			error = 1;
2925 			goto scsiformat_bailout;
2926 		}
2927 	}
2928 
2929 	if (timeout != 0)
2930 		use_timeout = timeout;
2931 
2932 	if (quiet == 0) {
2933 		fprintf(stdout, "Current format timeout is %d seconds\n",
2934 			use_timeout / 1000);
2935 	}
2936 
2937 	/*
2938 	 * If the user hasn't disabled questions and didn't specify a
2939 	 * timeout on the command line, ask them if they want the current
2940 	 * timeout.
2941 	 */
2942 	if ((ycount == 0)
2943 	 && (timeout == 0)) {
2944 		char str[1024];
2945 		int new_timeout = 0;
2946 
2947 		fprintf(stdout, "Enter new timeout in seconds or press\n"
2948 			"return to keep the current timeout [%d] ",
2949 			use_timeout / 1000);
2950 
2951 		if (fgets(str, sizeof(str), stdin) != NULL) {
2952 			if (str[0] != '\0')
2953 				new_timeout = atoi(str);
2954 		}
2955 
2956 		if (new_timeout != 0) {
2957 			use_timeout = new_timeout * 1000;
2958 			fprintf(stdout, "Using new timeout value %d\n",
2959 				use_timeout / 1000);
2960 		}
2961 	}
2962 
2963 	/*
2964 	 * Keep this outside the if block below to silence any unused
2965 	 * variable warnings.
2966 	 */
2967 	bzero(&fh, sizeof(fh));
2968 
2969 	/*
2970 	 * If we're in immediate mode, we've got to include the format
2971 	 * header
2972 	 */
2973 	if (immediate != 0) {
2974 		fh.byte2 = FU_DLH_IMMED;
2975 		data_ptr = (u_int8_t *)&fh;
2976 		dxfer_len = sizeof(fh);
2977 		byte2 = FU_FMT_DATA;
2978 	} else if (quiet == 0) {
2979 		fprintf(stdout, "Formatting...");
2980 		fflush(stdout);
2981 	}
2982 
2983 	scsi_format_unit(&ccb->csio,
2984 			 /* retries */ retry_count,
2985 			 /* cbfcnp */ NULL,
2986 			 /* tag_action */ MSG_SIMPLE_Q_TAG,
2987 			 /* byte2 */ byte2,
2988 			 /* ileave */ 0,
2989 			 /* data_ptr */ data_ptr,
2990 			 /* dxfer_len */ dxfer_len,
2991 			 /* sense_len */ SSD_FULL_SIZE,
2992 			 /* timeout */ use_timeout);
2993 
2994 	/* Disable freezing the device queue */
2995 	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
2996 
2997 	if (arglist & CAM_ARG_ERR_RECOVER)
2998 		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
2999 
3000 	if (((retval = cam_send_ccb(device, ccb)) < 0)
3001 	 || ((immediate == 0)
3002 	   && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP))) {
3003 		const char errstr[] = "error sending format command";
3004 
3005 		if (retval < 0)
3006 			warn(errstr);
3007 		else
3008 			warnx(errstr);
3009 
3010 		if (arglist & CAM_ARG_VERBOSE) {
3011 			cam_error_print(device, ccb, CAM_ESF_ALL,
3012 					CAM_EPF_ALL, stderr);
3013 		}
3014 		error = 1;
3015 		goto scsiformat_bailout;
3016 	}
3017 
3018 	/*
3019 	 * If we ran in non-immediate mode, we already checked for errors
3020 	 * above and printed out any necessary information.  If we're in
3021 	 * immediate mode, we need to loop through and get status
3022 	 * information periodically.
3023 	 */
3024 	if (immediate == 0) {
3025 		if (quiet == 0) {
3026 			fprintf(stdout, "Format Complete\n");
3027 		}
3028 		goto scsiformat_bailout;
3029 	}
3030 
3031 doreport:
3032 	do {
3033 		cam_status status;
3034 
3035 		bzero(&(&ccb->ccb_h)[1],
3036 		      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
3037 
3038 		/*
3039 		 * There's really no need to do error recovery or
3040 		 * retries here, since we're just going to sit in a
3041 		 * loop and wait for the device to finish formatting.
3042 		 */
3043 		scsi_test_unit_ready(&ccb->csio,
3044 				     /* retries */ 0,
3045 				     /* cbfcnp */ NULL,
3046 				     /* tag_action */ MSG_SIMPLE_Q_TAG,
3047 				     /* sense_len */ SSD_FULL_SIZE,
3048 				     /* timeout */ 5000);
3049 
3050 		/* Disable freezing the device queue */
3051 		ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
3052 
3053 		retval = cam_send_ccb(device, ccb);
3054 
3055 		/*
3056 		 * If we get an error from the ioctl, bail out.  SCSI
3057 		 * errors are expected.
3058 		 */
3059 		if (retval < 0) {
3060 			warn("error sending CAMIOCOMMAND ioctl");
3061 			if (arglist & CAM_ARG_VERBOSE) {
3062 				cam_error_print(device, ccb, CAM_ESF_ALL,
3063 						CAM_EPF_ALL, stderr);
3064 			}
3065 			error = 1;
3066 			goto scsiformat_bailout;
3067 		}
3068 
3069 		status = ccb->ccb_h.status & CAM_STATUS_MASK;
3070 
3071 		if ((status != CAM_REQ_CMP)
3072 		 && (status == CAM_SCSI_STATUS_ERROR)
3073 		 && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) {
3074 			struct scsi_sense_data *sense;
3075 			int error_code, sense_key, asc, ascq;
3076 
3077 			sense = &ccb->csio.sense_data;
3078 			scsi_extract_sense(sense, &error_code, &sense_key,
3079 					   &asc, &ascq);
3080 
3081 			/*
3082 			 * According to the SCSI-2 and SCSI-3 specs, a
3083 			 * drive that is in the middle of a format should
3084 			 * return NOT READY with an ASC of "logical unit
3085 			 * not ready, format in progress".  The sense key
3086 			 * specific bytes will then be a progress indicator.
3087 			 */
3088 			if ((sense_key == SSD_KEY_NOT_READY)
3089 			 && (asc == 0x04) && (ascq == 0x04)) {
3090 				if ((sense->extra_len >= 10)
3091 				 && ((sense->sense_key_spec[0] &
3092 				      SSD_SCS_VALID) != 0)
3093 				 && (quiet == 0)) {
3094 					int val;
3095 					u_int64_t percentage;
3096 
3097 					val = scsi_2btoul(
3098 						&sense->sense_key_spec[1]);
3099 					percentage = 10000 * val;
3100 
3101 					fprintf(stdout,
3102 						"\rFormatting:  %qd.%02qd %% "
3103 						"(%d/%d) done",
3104 						percentage / (0x10000 * 100),
3105 						(percentage / 0x10000) % 100,
3106 						val, 0x10000);
3107 					fflush(stdout);
3108 				} else if ((quiet == 0)
3109 					&& (++num_warnings <= 1)) {
3110 					warnx("Unexpected SCSI Sense Key "
3111 					      "Specific value returned "
3112 					      "during format:");
3113 					scsi_sense_print(device, &ccb->csio,
3114 							 stderr);
3115 					warnx("Unable to print status "
3116 					      "information, but format will "
3117 					      "proceed.");
3118 					warnx("will exit when format is "
3119 					      "complete");
3120 				}
3121 				sleep(1);
3122 			} else {
3123 				warnx("Unexpected SCSI error during format");
3124 				cam_error_print(device, ccb, CAM_ESF_ALL,
3125 						CAM_EPF_ALL, stderr);
3126 				error = 1;
3127 				goto scsiformat_bailout;
3128 			}
3129 
3130 		} else if (status != CAM_REQ_CMP) {
3131 			warnx("Unexpected CAM status %#x", status);
3132 			if (arglist & CAM_ARG_VERBOSE)
3133 				cam_error_print(device, ccb, CAM_ESF_ALL,
3134 						CAM_EPF_ALL, stderr);
3135 			error = 1;
3136 			goto scsiformat_bailout;
3137 		}
3138 
3139 	} while((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP);
3140 
3141 	if (quiet == 0)
3142 		fprintf(stdout, "\nFormat Complete\n");
3143 
3144 scsiformat_bailout:
3145 
3146 	cam_freeccb(ccb);
3147 
3148 	return(error);
3149 }
3150 
3151 static int
3152 scsireportluns(struct cam_device *device, int argc, char **argv,
3153 	       char *combinedopt, int retry_count, int timeout)
3154 {
3155 	union ccb *ccb;
3156 	int c, countonly, lunsonly;
3157 	struct scsi_report_luns_data *lundata;
3158 	int alloc_len;
3159 	uint8_t report_type;
3160 	uint32_t list_len, i, j;
3161 	int retval;
3162 
3163 	retval = 0;
3164 	lundata = NULL;
3165 	report_type = RPL_REPORT_DEFAULT;
3166 	ccb = cam_getccb(device);
3167 
3168 	if (ccb == NULL) {
3169 		warnx("%s: error allocating ccb", __func__);
3170 		return (1);
3171 	}
3172 
3173 	bzero(&(&ccb->ccb_h)[1],
3174 	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
3175 
3176 	countonly = 0;
3177 	lunsonly = 0;
3178 
3179 	while ((c = getopt(argc, argv, combinedopt)) != -1) {
3180 		switch (c) {
3181 		case 'c':
3182 			countonly++;
3183 			break;
3184 		case 'l':
3185 			lunsonly++;
3186 			break;
3187 		case 'r':
3188 			if (strcasecmp(optarg, "default") == 0)
3189 				report_type = RPL_REPORT_DEFAULT;
3190 			else if (strcasecmp(optarg, "wellknown") == 0)
3191 				report_type = RPL_REPORT_WELLKNOWN;
3192 			else if (strcasecmp(optarg, "all") == 0)
3193 				report_type = RPL_REPORT_ALL;
3194 			else {
3195 				warnx("%s: invalid report type \"%s\"",
3196 				      __func__, optarg);
3197 				retval = 1;
3198 				goto bailout;
3199 			}
3200 			break;
3201 		default:
3202 			break;
3203 		}
3204 	}
3205 
3206 	if ((countonly != 0)
3207 	 && (lunsonly != 0)) {
3208 		warnx("%s: you can only specify one of -c or -l", __func__);
3209 		retval = 1;
3210 		goto bailout;
3211 	}
3212 	/*
3213 	 * According to SPC-4, the allocation length must be at least 16
3214 	 * bytes -- enough for the header and one LUN.
3215 	 */
3216 	alloc_len = sizeof(*lundata) + 8;
3217 
3218 retry:
3219 
3220 	lundata = malloc(alloc_len);
3221 
3222 	if (lundata == NULL) {
3223 		warn("%s: error mallocing %d bytes", __func__, alloc_len);
3224 		retval = 1;
3225 		goto bailout;
3226 	}
3227 
3228 	scsi_report_luns(&ccb->csio,
3229 			 /*retries*/ retry_count,
3230 			 /*cbfcnp*/ NULL,
3231 			 /*tag_action*/ MSG_SIMPLE_Q_TAG,
3232 			 /*select_report*/ report_type,
3233 			 /*rpl_buf*/ lundata,
3234 			 /*alloc_len*/ alloc_len,
3235 			 /*sense_len*/ SSD_FULL_SIZE,
3236 			 /*timeout*/ timeout ? timeout : 5000);
3237 
3238 	/* Disable freezing the device queue */
3239 	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
3240 
3241 	if (arglist & CAM_ARG_ERR_RECOVER)
3242 		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
3243 
3244 	if (cam_send_ccb(device, ccb) < 0) {
3245 		warn("error sending REPORT LUNS command");
3246 
3247 		if (arglist & CAM_ARG_VERBOSE)
3248 			cam_error_print(device, ccb, CAM_ESF_ALL,
3249 					CAM_EPF_ALL, stderr);
3250 
3251 		retval = 1;
3252 		goto bailout;
3253 	}
3254 
3255 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3256 		cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
3257 		retval = 1;
3258 		goto bailout;
3259 	}
3260 
3261 
3262 	list_len = scsi_4btoul(lundata->length);
3263 
3264 	/*
3265 	 * If we need to list the LUNs, and our allocation
3266 	 * length was too short, reallocate and retry.
3267 	 */
3268 	if ((countonly == 0)
3269 	 && (list_len > (alloc_len - sizeof(*lundata)))) {
3270 		alloc_len = list_len + sizeof(*lundata);
3271 		free(lundata);
3272 		goto retry;
3273 	}
3274 
3275 	if (lunsonly == 0)
3276 		fprintf(stdout, "%u LUN%s found\n", list_len / 8,
3277 			((list_len / 8) > 1) ? "s" : "");
3278 
3279 	if (countonly != 0)
3280 		goto bailout;
3281 
3282 	for (i = 0; i < (list_len / 8); i++) {
3283 		int no_more;
3284 
3285 		no_more = 0;
3286 		for (j = 0; j < sizeof(lundata->luns[i].lundata); j += 2) {
3287 			if (j != 0)
3288 				fprintf(stdout, ",");
3289 			switch (lundata->luns[i].lundata[j] &
3290 				RPL_LUNDATA_ATYP_MASK) {
3291 			case RPL_LUNDATA_ATYP_PERIPH:
3292 				if ((lundata->luns[i].lundata[j] &
3293 				    RPL_LUNDATA_PERIPH_BUS_MASK) != 0)
3294 					fprintf(stdout, "%d:",
3295 						lundata->luns[i].lundata[j] &
3296 						RPL_LUNDATA_PERIPH_BUS_MASK);
3297 				else if ((j == 0)
3298 				      && ((lundata->luns[i].lundata[j+2] &
3299 					  RPL_LUNDATA_PERIPH_BUS_MASK) == 0))
3300 					no_more = 1;
3301 
3302 				fprintf(stdout, "%d",
3303 					lundata->luns[i].lundata[j+1]);
3304 				break;
3305 			case RPL_LUNDATA_ATYP_FLAT: {
3306 				uint8_t tmplun[2];
3307 				tmplun[0] = lundata->luns[i].lundata[j] &
3308 					RPL_LUNDATA_FLAT_LUN_MASK;
3309 				tmplun[1] = lundata->luns[i].lundata[j+1];
3310 
3311 				fprintf(stdout, "%d", scsi_2btoul(tmplun));
3312 				no_more = 1;
3313 				break;
3314 			}
3315 			case RPL_LUNDATA_ATYP_LUN:
3316 				fprintf(stdout, "%d:%d:%d",
3317 					(lundata->luns[i].lundata[j+1] &
3318 					RPL_LUNDATA_LUN_BUS_MASK) >> 5,
3319 					lundata->luns[i].lundata[j] &
3320 					RPL_LUNDATA_LUN_TARG_MASK,
3321 					lundata->luns[i].lundata[j+1] &
3322 					RPL_LUNDATA_LUN_LUN_MASK);
3323 				break;
3324 			case RPL_LUNDATA_ATYP_EXTLUN: {
3325 				int field_len, field_len_code, eam_code;
3326 
3327 				eam_code = lundata->luns[i].lundata[j] &
3328 					RPL_LUNDATA_EXT_EAM_MASK;
3329 				field_len_code = (lundata->luns[i].lundata[j] &
3330 					RPL_LUNDATA_EXT_LEN_MASK) >> 4;
3331 				field_len = field_len_code * 2;
3332 
3333 				if ((eam_code == RPL_LUNDATA_EXT_EAM_WK)
3334 				 && (field_len_code == 0x00)) {
3335 					fprintf(stdout, "%d",
3336 						lundata->luns[i].lundata[j+1]);
3337 				} else if ((eam_code ==
3338 					    RPL_LUNDATA_EXT_EAM_NOT_SPEC)
3339 					&& (field_len_code == 0x03)) {
3340 					uint8_t tmp_lun[8];
3341 
3342 					/*
3343 					 * This format takes up all 8 bytes.
3344 					 * If we aren't starting at offset 0,
3345 					 * that's a bug.
3346 					 */
3347 					if (j != 0) {
3348 						fprintf(stdout, "Invalid "
3349 							"offset %d for "
3350 							"Extended LUN not "
3351 							"specified format", j);
3352 						no_more = 1;
3353 						break;
3354 					}
3355 					bzero(tmp_lun, sizeof(tmp_lun));
3356 					bcopy(&lundata->luns[i].lundata[j+1],
3357 					      &tmp_lun[1], sizeof(tmp_lun) - 1);
3358 					fprintf(stdout, "%#jx",
3359 					       (intmax_t)scsi_8btou64(tmp_lun));
3360 					no_more = 1;
3361 				} else {
3362 					fprintf(stderr, "Unknown Extended LUN"
3363 						"Address method %#x, length "
3364 						"code %#x", eam_code,
3365 						field_len_code);
3366 					no_more = 1;
3367 				}
3368 				break;
3369 			}
3370 			default:
3371 				fprintf(stderr, "Unknown LUN address method "
3372 					"%#x\n", lundata->luns[i].lundata[0] &
3373 					RPL_LUNDATA_ATYP_MASK);
3374 				break;
3375 			}
3376 			/*
3377 			 * For the flat addressing method, there are no
3378 			 * other levels after it.
3379 			 */
3380 			if (no_more != 0)
3381 				break;
3382 		}
3383 		fprintf(stdout, "\n");
3384 	}
3385 
3386 bailout:
3387 
3388 	cam_freeccb(ccb);
3389 
3390 	free(lundata);
3391 
3392 	return (retval);
3393 }
3394 
3395 #endif /* MINIMALISTIC */
3396 
3397 void
3398 usage(int verbose)
3399 {
3400 	fprintf(verbose ? stdout : stderr,
3401 "usage:  camcontrol <command>  [device id][generic args][command args]\n"
3402 "        camcontrol devlist    [-v]\n"
3403 #ifndef MINIMALISTIC
3404 "        camcontrol periphlist [dev_id][-n dev_name] [-u unit]\n"
3405 "        camcontrol tur        [dev_id][generic args]\n"
3406 "        camcontrol inquiry    [dev_id][generic args] [-D] [-S] [-R]\n"
3407 "        camcontrol reportluns [dev_id][generic args] [-c] [-l] [-r report]\n"
3408 "        camcontrol start      [dev_id][generic args]\n"
3409 "        camcontrol stop       [dev_id][generic args]\n"
3410 "        camcontrol load       [dev_id][generic args]\n"
3411 "        camcontrol eject      [dev_id][generic args]\n"
3412 #endif /* MINIMALISTIC */
3413 "        camcontrol rescan     <all | bus[:target:lun]>\n"
3414 "        camcontrol reset      <all | bus[:target:lun]>\n"
3415 #ifndef MINIMALISTIC
3416 "        camcontrol defects    [dev_id][generic args] <-f format> [-P][-G]\n"
3417 "        camcontrol modepage   [dev_id][generic args] <-m page | -l>\n"
3418 "                              [-P pagectl][-e | -b][-d]\n"
3419 "        camcontrol cmd        [dev_id][generic args] <-c cmd [args]>\n"
3420 "                              [-i len fmt|-o len fmt [args]]\n"
3421 "        camcontrol debug      [-I][-P][-T][-S][-X][-c]\n"
3422 "                              <all|bus[:target[:lun]]|off>\n"
3423 "        camcontrol tags       [dev_id][generic args] [-N tags] [-q] [-v]\n"
3424 "        camcontrol negotiate  [dev_id][generic args] [-a][-c]\n"
3425 "                              [-D <enable|disable>][-O offset][-q]\n"
3426 "                              [-R syncrate][-v][-T <enable|disable>]\n"
3427 "                              [-U][-W bus_width]\n"
3428 "        camcontrol format     [dev_id][generic args][-q][-r][-w][-y]\n"
3429 #endif /* MINIMALISTIC */
3430 "        camcontrol help\n");
3431 	if (!verbose)
3432 		return;
3433 #ifndef MINIMALISTIC
3434 	fprintf(stdout,
3435 "Specify one of the following options:\n"
3436 "devlist     list all CAM devices\n"
3437 "periphlist  list all CAM peripheral drivers attached to a device\n"
3438 "tur         send a test unit ready to the named device\n"
3439 "inquiry     send a SCSI inquiry command to the named device\n"
3440 "reportluns  send a SCSI report luns command to the device\n"
3441 "start       send a Start Unit command to the device\n"
3442 "stop        send a Stop Unit command to the device\n"
3443 "load        send a Start Unit command to the device with the load bit set\n"
3444 "eject       send a Stop Unit command to the device with the eject bit set\n"
3445 "rescan      rescan all busses, the given bus, or bus:target:lun\n"
3446 "reset       reset all busses, the given bus, or bus:target:lun\n"
3447 "defects     read the defect list of the specified device\n"
3448 "modepage    display or edit (-e) the given mode page\n"
3449 "cmd         send the given scsi command, may need -i or -o as well\n"
3450 "debug       turn debugging on/off for a bus, target, or lun, or all devices\n"
3451 "tags        report or set the number of transaction slots for a device\n"
3452 "negotiate   report or set device negotiation parameters\n"
3453 "format      send the SCSI FORMAT UNIT command to the named device\n"
3454 "help        this message\n"
3455 "Device Identifiers:\n"
3456 "bus:target        specify the bus and target, lun defaults to 0\n"
3457 "bus:target:lun    specify the bus, target and lun\n"
3458 "deviceUNIT        specify the device name, like \"da4\" or \"cd2\"\n"
3459 "Generic arguments:\n"
3460 "-v                be verbose, print out sense information\n"
3461 "-t timeout        command timeout in seconds, overrides default timeout\n"
3462 "-n dev_name       specify device name, e.g. \"da\", \"cd\"\n"
3463 "-u unit           specify unit number, e.g. \"0\", \"5\"\n"
3464 "-E                have the kernel attempt to perform SCSI error recovery\n"
3465 "-C count          specify the SCSI command retry count (needs -E to work)\n"
3466 "modepage arguments:\n"
3467 "-l                list all available mode pages\n"
3468 "-m page           specify the mode page to view or edit\n"
3469 "-e                edit the specified mode page\n"
3470 "-b                force view to binary mode\n"
3471 "-d                disable block descriptors for mode sense\n"
3472 "-P pgctl          page control field 0-3\n"
3473 "defects arguments:\n"
3474 "-f format         specify defect list format (block, bfi or phys)\n"
3475 "-G                get the grown defect list\n"
3476 "-P                get the permanant defect list\n"
3477 "inquiry arguments:\n"
3478 "-D                get the standard inquiry data\n"
3479 "-S                get the serial number\n"
3480 "-R                get the transfer rate, etc.\n"
3481 "reportluns arguments:\n"
3482 "-c                only report a count of available LUNs\n"
3483 "-l                only print out luns, and not a count\n"
3484 "-r <reporttype>   specify \"default\", \"wellknown\" or \"all\"\n"
3485 "cmd arguments:\n"
3486 "-c cdb [args]     specify the SCSI CDB\n"
3487 "-i len fmt        specify input data and input data format\n"
3488 "-o len fmt [args] specify output data and output data fmt\n"
3489 "debug arguments:\n"
3490 "-I                CAM_DEBUG_INFO -- scsi commands, errors, data\n"
3491 "-T                CAM_DEBUG_TRACE -- routine flow tracking\n"
3492 "-S                CAM_DEBUG_SUBTRACE -- internal routine command flow\n"
3493 "-c                CAM_DEBUG_CDB -- print out SCSI CDBs only\n"
3494 "tags arguments:\n"
3495 "-N tags           specify the number of tags to use for this device\n"
3496 "-q                be quiet, don't report the number of tags\n"
3497 "-v                report a number of tag-related parameters\n"
3498 "negotiate arguments:\n"
3499 "-a                send a test unit ready after negotiation\n"
3500 "-c                report/set current negotiation settings\n"
3501 "-D <arg>          \"enable\" or \"disable\" disconnection\n"
3502 "-O offset         set command delay offset\n"
3503 "-q                be quiet, don't report anything\n"
3504 "-R syncrate       synchronization rate in MHz\n"
3505 "-T <arg>          \"enable\" or \"disable\" tagged queueing\n"
3506 "-U                report/set user negotiation settings\n"
3507 "-W bus_width      set the bus width in bits (8, 16 or 32)\n"
3508 "-v                also print a Path Inquiry CCB for the controller\n"
3509 "format arguments:\n"
3510 "-q                be quiet, don't print status messages\n"
3511 "-r                run in report only mode\n"
3512 "-w                don't send immediate format command\n"
3513 "-y                don't ask any questions\n");
3514 #endif /* MINIMALISTIC */
3515 }
3516 
3517 int
3518 main(int argc, char **argv)
3519 {
3520 	int c;
3521 	char *device = NULL;
3522 	int unit = 0;
3523 	struct cam_device *cam_dev = NULL;
3524 	int timeout = 0, retry_count = 1;
3525 	camcontrol_optret optreturn;
3526 	char *tstr;
3527 	const char *mainopt = "C:En:t:u:v";
3528 	const char *subopt = NULL;
3529 	char combinedopt[256];
3530 	int error = 0, optstart = 2;
3531 	int devopen = 1;
3532 
3533 	cmdlist = CAM_CMD_NONE;
3534 	arglist = CAM_ARG_NONE;
3535 
3536 	if (argc < 2) {
3537 		usage(0);
3538 		exit(1);
3539 	}
3540 
3541 	/*
3542 	 * Get the base option.
3543 	 */
3544 	optreturn = getoption(argv[1], &cmdlist, &arglist, &subopt);
3545 
3546 	if (optreturn == CC_OR_AMBIGUOUS) {
3547 		warnx("ambiguous option %s", argv[1]);
3548 		usage(0);
3549 		exit(1);
3550 	} else if (optreturn == CC_OR_NOT_FOUND) {
3551 		warnx("option %s not found", argv[1]);
3552 		usage(0);
3553 		exit(1);
3554 	}
3555 
3556 	/*
3557 	 * Ahh, getopt(3) is a pain.
3558 	 *
3559 	 * This is a gross hack.  There really aren't many other good
3560 	 * options (excuse the pun) for parsing options in a situation like
3561 	 * this.  getopt is kinda braindead, so you end up having to run
3562 	 * through the options twice, and give each invocation of getopt
3563 	 * the option string for the other invocation.
3564 	 *
3565 	 * You would think that you could just have two groups of options.
3566 	 * The first group would get parsed by the first invocation of
3567 	 * getopt, and the second group would get parsed by the second
3568 	 * invocation of getopt.  It doesn't quite work out that way.  When
3569 	 * the first invocation of getopt finishes, it leaves optind pointing
3570 	 * to the argument _after_ the first argument in the second group.
3571 	 * So when the second invocation of getopt comes around, it doesn't
3572 	 * recognize the first argument it gets and then bails out.
3573 	 *
3574 	 * A nice alternative would be to have a flag for getopt that says
3575 	 * "just keep parsing arguments even when you encounter an unknown
3576 	 * argument", but there isn't one.  So there's no real clean way to
3577 	 * easily parse two sets of arguments without having one invocation
3578 	 * of getopt know about the other.
3579 	 *
3580 	 * Without this hack, the first invocation of getopt would work as
3581 	 * long as the generic arguments are first, but the second invocation
3582 	 * (in the subfunction) would fail in one of two ways.  In the case
3583 	 * where you don't set optreset, it would fail because optind may be
3584 	 * pointing to the argument after the one it should be pointing at.
3585 	 * In the case where you do set optreset, and reset optind, it would
3586 	 * fail because getopt would run into the first set of options, which
3587 	 * it doesn't understand.
3588 	 *
3589 	 * All of this would "sort of" work if you could somehow figure out
3590 	 * whether optind had been incremented one option too far.  The
3591 	 * mechanics of that, however, are more daunting than just giving
3592 	 * both invocations all of the expect options for either invocation.
3593 	 *
3594 	 * Needless to say, I wouldn't mind if someone invented a better
3595 	 * (non-GPL!) command line parsing interface than getopt.  I
3596 	 * wouldn't mind if someone added more knobs to getopt to make it
3597 	 * work better.  Who knows, I may talk myself into doing it someday,
3598 	 * if the standards weenies let me.  As it is, it just leads to
3599 	 * hackery like this and causes people to avoid it in some cases.
3600 	 *
3601 	 * KDM, September 8th, 1998
3602 	 */
3603 	if (subopt != NULL)
3604 		sprintf(combinedopt, "%s%s", mainopt, subopt);
3605 	else
3606 		sprintf(combinedopt, "%s", mainopt);
3607 
3608 	/*
3609 	 * For these options we do not parse optional device arguments and
3610 	 * we do not open a passthrough device.
3611 	 */
3612 	if ((cmdlist == CAM_CMD_RESCAN)
3613 	 || (cmdlist == CAM_CMD_RESET)
3614 	 || (cmdlist == CAM_CMD_DEVTREE)
3615 	 || (cmdlist == CAM_CMD_USAGE)
3616 	 || (cmdlist == CAM_CMD_DEBUG))
3617 		devopen = 0;
3618 
3619 #ifndef MINIMALISTIC
3620 	if ((devopen == 1)
3621 	 && (argc > 2 && argv[2][0] != '-')) {
3622 		char name[30];
3623 		int rv;
3624 
3625 		/*
3626 		 * First catch people who try to do things like:
3627 		 * camcontrol tur /dev/da0
3628 		 * camcontrol doesn't take device nodes as arguments.
3629 		 */
3630 		if (argv[2][0] == '/') {
3631 			warnx("%s is not a valid device identifier", argv[2]);
3632 			errx(1, "please read the camcontrol(8) man page");
3633 		} else if (isdigit(argv[2][0])) {
3634 			/* device specified as bus:target[:lun] */
3635 			rv = parse_btl(argv[2], &bus, &target, &lun, &arglist);
3636 			if (rv < 2)
3637 				errx(1, "numeric device specification must "
3638 				     "be either bus:target, or "
3639 				     "bus:target:lun");
3640 			/* default to 0 if lun was not specified */
3641 			if ((arglist & CAM_ARG_LUN) == 0) {
3642 				lun = 0;
3643 				arglist |= CAM_ARG_LUN;
3644 			}
3645 			optstart++;
3646 		} else {
3647 			if (cam_get_device(argv[2], name, sizeof name, &unit)
3648 			    == -1)
3649 				errx(1, "%s", cam_errbuf);
3650 			device = strdup(name);
3651 			arglist |= CAM_ARG_DEVICE | CAM_ARG_UNIT;
3652 			optstart++;
3653 		}
3654 	}
3655 #endif /* MINIMALISTIC */
3656 	/*
3657 	 * Start getopt processing at argv[2/3], since we've already
3658 	 * accepted argv[1..2] as the command name, and as a possible
3659 	 * device name.
3660 	 */
3661 	optind = optstart;
3662 
3663 	/*
3664 	 * Now we run through the argument list looking for generic
3665 	 * options, and ignoring options that possibly belong to
3666 	 * subfunctions.
3667 	 */
3668 	while ((c = getopt(argc, argv, combinedopt))!= -1){
3669 		switch(c) {
3670 			case 'C':
3671 				retry_count = strtol(optarg, NULL, 0);
3672 				if (retry_count < 0)
3673 					errx(1, "retry count %d is < 0",
3674 					     retry_count);
3675 				arglist |= CAM_ARG_RETRIES;
3676 				break;
3677 			case 'E':
3678 				arglist |= CAM_ARG_ERR_RECOVER;
3679 				break;
3680 			case 'n':
3681 				arglist |= CAM_ARG_DEVICE;
3682 				tstr = optarg;
3683 				while (isspace(*tstr) && (*tstr != '\0'))
3684 					tstr++;
3685 				device = (char *)strdup(tstr);
3686 				break;
3687 			case 't':
3688 				timeout = strtol(optarg, NULL, 0);
3689 				if (timeout < 0)
3690 					errx(1, "invalid timeout %d", timeout);
3691 				/* Convert the timeout from seconds to ms */
3692 				timeout *= 1000;
3693 				arglist |= CAM_ARG_TIMEOUT;
3694 				break;
3695 			case 'u':
3696 				arglist |= CAM_ARG_UNIT;
3697 				unit = strtol(optarg, NULL, 0);
3698 				break;
3699 			case 'v':
3700 				arglist |= CAM_ARG_VERBOSE;
3701 				break;
3702 			default:
3703 				break;
3704 		}
3705 	}
3706 
3707 #ifndef MINIMALISTIC
3708 	/*
3709 	 * For most commands we'll want to open the passthrough device
3710 	 * associated with the specified device.  In the case of the rescan
3711 	 * commands, we don't use a passthrough device at all, just the
3712 	 * transport layer device.
3713 	 */
3714 	if (devopen == 1) {
3715 		if (((arglist & (CAM_ARG_BUS|CAM_ARG_TARGET)) == 0)
3716 		 && (((arglist & CAM_ARG_DEVICE) == 0)
3717 		  || ((arglist & CAM_ARG_UNIT) == 0))) {
3718 			errx(1, "subcommand \"%s\" requires a valid device "
3719 			     "identifier", argv[1]);
3720 		}
3721 
3722 		if ((cam_dev = ((arglist & (CAM_ARG_BUS | CAM_ARG_TARGET))?
3723 				cam_open_btl(bus, target, lun, O_RDWR, NULL) :
3724 				cam_open_spec_device(device,unit,O_RDWR,NULL)))
3725 		     == NULL)
3726 			errx(1,"%s", cam_errbuf);
3727 	}
3728 #endif /* MINIMALISTIC */
3729 
3730 	/*
3731 	 * Reset optind to 2, and reset getopt, so these routines can parse
3732 	 * the arguments again.
3733 	 */
3734 	optind = optstart;
3735 	optreset = 1;
3736 
3737 	switch(cmdlist) {
3738 #ifndef MINIMALISTIC
3739 		case CAM_CMD_DEVLIST:
3740 			error = getdevlist(cam_dev);
3741 			break;
3742 #endif /* MINIMALISTIC */
3743 		case CAM_CMD_DEVTREE:
3744 			error = getdevtree();
3745 			break;
3746 #ifndef MINIMALISTIC
3747 		case CAM_CMD_TUR:
3748 			error = testunitready(cam_dev, retry_count, timeout, 0);
3749 			break;
3750 		case CAM_CMD_INQUIRY:
3751 			error = scsidoinquiry(cam_dev, argc, argv, combinedopt,
3752 					      retry_count, timeout);
3753 			break;
3754 		case CAM_CMD_STARTSTOP:
3755 			error = scsistart(cam_dev, arglist & CAM_ARG_START_UNIT,
3756 					  arglist & CAM_ARG_EJECT, retry_count,
3757 					  timeout);
3758 			break;
3759 #endif /* MINIMALISTIC */
3760 		case CAM_CMD_RESCAN:
3761 			error = dorescan_or_reset(argc, argv, 1);
3762 			break;
3763 		case CAM_CMD_RESET:
3764 			error = dorescan_or_reset(argc, argv, 0);
3765 			break;
3766 #ifndef MINIMALISTIC
3767 		case CAM_CMD_READ_DEFECTS:
3768 			error = readdefects(cam_dev, argc, argv, combinedopt,
3769 					    retry_count, timeout);
3770 			break;
3771 		case CAM_CMD_MODE_PAGE:
3772 			modepage(cam_dev, argc, argv, combinedopt,
3773 				 retry_count, timeout);
3774 			break;
3775 		case CAM_CMD_SCSI_CMD:
3776 			error = scsicmd(cam_dev, argc, argv, combinedopt,
3777 					retry_count, timeout);
3778 			break;
3779 		case CAM_CMD_DEBUG:
3780 			error = camdebug(argc, argv, combinedopt);
3781 			break;
3782 		case CAM_CMD_TAG:
3783 			error = tagcontrol(cam_dev, argc, argv, combinedopt);
3784 			break;
3785 		case CAM_CMD_RATE:
3786 			error = ratecontrol(cam_dev, retry_count, timeout,
3787 					    argc, argv, combinedopt);
3788 			break;
3789 		case CAM_CMD_FORMAT:
3790 			error = scsiformat(cam_dev, argc, argv,
3791 					   combinedopt, retry_count, timeout);
3792 			break;
3793 		case CAM_CMD_REPORTLUNS:
3794 			error = scsireportluns(cam_dev, argc, argv,
3795 					       combinedopt, retry_count,
3796 					       timeout);
3797 			break;
3798 #endif /* MINIMALISTIC */
3799 		case CAM_CMD_USAGE:
3800 			usage(1);
3801 			break;
3802 		default:
3803 			usage(0);
3804 			error = 1;
3805 			break;
3806 	}
3807 
3808 	if (cam_dev != NULL)
3809 		cam_close_device(cam_dev);
3810 
3811 	exit(error);
3812 }
3813