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