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