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