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