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