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