]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sbin/camcontrol/camcontrol.c
MFC r196657:
[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[] = "c:i:o:";
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 scsixferrate(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 = scsixferrate(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 scsixferrate(struct cam_device *device)
877 {
878         u_int32_t freq = 0;
879         u_int32_t speed = 0;
880         union ccb *ccb;
881         u_int mb;
882         int retval = 0;
883
884         ccb = cam_getccb(device);
885
886         if (ccb == NULL) {
887                 warnx("couldn't allocate CCB");
888                 return(1);
889         }
890
891         bzero(&(&ccb->ccb_h)[1],
892               sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr));
893
894         ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
895         ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS;
896
897         if (((retval = cam_send_ccb(device, ccb)) < 0)
898          || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
899                 const char error_string[] = "error getting transfer settings";
900
901                 if (retval < 0)
902                         warn(error_string);
903                 else
904                         warnx(error_string);
905
906                 if (arglist & CAM_ARG_VERBOSE)
907                         cam_error_print(device, ccb, CAM_ESF_ALL,
908                                         CAM_EPF_ALL, stderr);
909
910                 retval = 1;
911
912                 goto xferrate_bailout;
913
914         }
915
916         if (ccb->cts.transport == XPORT_SPI) {
917                 struct ccb_trans_settings_spi *spi =
918                     &ccb->cts.xport_specific.spi;
919
920                 if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) {
921                         freq = scsi_calc_syncsrate(spi->sync_period);
922                         speed = freq;
923                 } else {
924                         struct ccb_pathinq cpi;
925
926                         retval = get_cpi(device, &cpi);
927                         if (retval == 0) {
928                                 speed = cpi.base_transfer_speed;
929                                 freq = 0;
930                         }
931                 }
932
933                 fprintf(stdout, "%s%d: ", device->device_name,
934                         device->dev_unit_num);
935
936                 if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
937                         speed *= (0x01 << spi->bus_width);
938                 }
939
940                 mb = speed / 1000;
941
942                 if (mb > 0) 
943                         fprintf(stdout, "%d.%03dMB/s transfers ",
944                                 mb, speed % 1000);
945                 else
946                         fprintf(stdout, "%dKB/s transfers ",
947                                 speed);
948
949                 if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
950                  && (spi->sync_offset != 0))
951                         fprintf(stdout, "(%d.%03dMHz, offset %d", freq / 1000,
952                                 freq % 1000, spi->sync_offset);
953
954                 if (((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0)
955                  && (spi->bus_width > 0)) {
956                         if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
957                          && (spi->sync_offset != 0)) {
958                                 fprintf(stdout, ", ");
959                         } else {
960                                 fprintf(stdout, " (");
961                         }
962                         fprintf(stdout, "%dbit)", 8 * (0x01 << spi->bus_width));
963                 } else if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
964                  && (spi->sync_offset != 0)) {
965                         fprintf(stdout, ")");
966                 }
967         } else {
968                 struct ccb_pathinq cpi;
969
970                 retval = get_cpi(device, &cpi);
971
972                 if (retval != 0)
973                         goto xferrate_bailout;
974
975                 speed = cpi.base_transfer_speed;
976                 freq = 0;
977
978                 mb = speed / 1000;
979
980                 if (mb > 0) 
981                         fprintf(stdout, "%d.%03dMB/s transfers ",
982                                 mb, speed % 1000);
983                 else
984                         fprintf(stdout, "%dKB/s transfers ",
985                                 speed);
986         }
987
988         if (ccb->cts.protocol == PROTO_SCSI) {
989                 struct ccb_trans_settings_scsi *scsi =
990                     &ccb->cts.proto_specific.scsi;
991                 if (scsi->valid & CTS_SCSI_VALID_TQ) {
992                         if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) {
993                                 fprintf(stdout, ", Command Queueing Enabled");
994                         }
995                 }
996         }
997
998         fprintf(stdout, "\n");
999
1000 xferrate_bailout:
1001
1002         cam_freeccb(ccb);
1003
1004         return(retval);
1005 }
1006
1007 static void
1008 atacapprint(struct ata_params *parm)
1009 {
1010         u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
1011                                 ((u_int32_t)parm->lba_size_2 << 16);
1012
1013         u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
1014                                 ((u_int64_t)parm->lba_size48_2 << 16) |
1015                                 ((u_int64_t)parm->lba_size48_3 << 32) |
1016                                 ((u_int64_t)parm->lba_size48_4 << 48);
1017
1018         printf("\n");
1019         printf("protocol              ");
1020         printf("ATA/ATAPI-%d", ata_version(parm->version_major));
1021         if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
1022                 if (parm->satacapabilities & ATA_SATA_GEN2)
1023                         printf(" SATA 2.x\n");
1024                 else if (parm->satacapabilities & ATA_SATA_GEN1)
1025                         printf(" SATA 1.x\n");
1026                 else
1027                         printf(" SATA x.x\n");
1028         }
1029         else
1030                 printf("\n");
1031         printf("device model          %.40s\n", parm->model);
1032         printf("serial number         %.20s\n", parm->serial);
1033         printf("firmware revision     %.8s\n", parm->revision);
1034
1035         printf("cylinders             %d\n", parm->cylinders);
1036         printf("heads                 %d\n", parm->heads);
1037         printf("sectors/track         %d\n", parm->sectors);
1038
1039         if (parm->config == ATA_PROTO_CFA ||
1040             (parm->support.command2 & ATA_SUPPORT_CFA))
1041                 printf("CFA supported\n");
1042
1043         printf("LBA%ssupported         ",
1044                 parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not ");
1045         if (lbasize)
1046                 printf("%d sectors\n", lbasize);
1047         else
1048                 printf("\n");
1049
1050         printf("LBA48%ssupported       ",
1051                 parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not ");
1052         if (lbasize48)
1053                 printf("%ju sectors\n", (uintmax_t)lbasize48);
1054         else
1055                 printf("\n");
1056
1057         printf("PIO supported         PIO");
1058         if (parm->atavalid & ATA_FLAG_64_70) {
1059                 if (parm->apiomodes & 0x02)
1060                         printf("4");
1061                 else if (parm->apiomodes & 0x01)
1062                         printf("3");
1063         } else if (parm->mwdmamodes & 0x04)
1064                 printf("4");
1065         else if (parm->mwdmamodes & 0x02)
1066                 printf("3");
1067         else if (parm->mwdmamodes & 0x01)
1068                 printf("2");
1069         else if ((parm->retired_piomode & ATA_RETIRED_PIO_MASK) == 0x200)
1070                 printf("2");
1071         else if ((parm->retired_piomode & ATA_RETIRED_PIO_MASK) == 0x100)
1072                 printf("1");
1073         else
1074                 printf("0");
1075         printf("\n");
1076
1077         printf("DMA%ssupported         ",
1078                 parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not ");
1079         if (parm->capabilities1 & ATA_SUPPORT_DMA) {
1080                 if (parm->mwdmamodes & 0xff) {
1081                         printf("WDMA");
1082                         if (parm->mwdmamodes & 0x04)
1083                                 printf("2");
1084                         else if (parm->mwdmamodes & 0x02)
1085                                 printf("1");
1086                         else if (parm->mwdmamodes & 0x01)
1087                                 printf("0");
1088                         printf(" ");
1089                 }
1090                 if ((parm->atavalid & ATA_FLAG_88) &&
1091                     (parm->udmamodes & 0xff)) {
1092                         printf("UDMA");
1093                         if (parm->udmamodes & 0x40)
1094                                 printf("6");
1095                         else if (parm->udmamodes & 0x20)
1096                                 printf("5");
1097                         else if (parm->udmamodes & 0x10)
1098                                 printf("4");
1099                         else if (parm->udmamodes & 0x08)
1100                                 printf("3");
1101                         else if (parm->udmamodes & 0x04)
1102                                 printf("2");
1103                         else if (parm->udmamodes & 0x02)
1104                                 printf("1");
1105                         else if (parm->udmamodes & 0x01)
1106                                 printf("0");
1107                         printf(" ");
1108                 }
1109         }
1110         printf("\n");
1111
1112         printf("overlap%ssupported\n",
1113                 parm->capabilities1 & ATA_SUPPORT_OVERLAP ? " " : " not ");
1114
1115         printf("\nFeature                      "
1116                 "Support  Enable    Value           Vendor\n");
1117
1118         printf("write cache                    %s       %s\n",
1119                 parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no",
1120                 parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no");
1121
1122         printf("read ahead                     %s       %s\n",
1123                 parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no",
1124                 parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no");
1125
1126         if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
1127                 printf("Native Command Queuing (NCQ)   %s       "
1128                         "       %d/0x%02X\n",
1129                         parm->satacapabilities & ATA_SUPPORT_NCQ ?
1130                                 "yes" : "no",
1131                         (parm->satacapabilities & ATA_SUPPORT_NCQ) ?
1132                                 ATA_QUEUE_LEN(parm->queue) : 0,
1133                         (parm->satacapabilities & ATA_SUPPORT_NCQ) ?
1134                                 ATA_QUEUE_LEN(parm->queue) : 0);
1135         }
1136         printf("Tagged Command Queuing (TCQ)   %s       %s      %d/0x%02X\n",
1137                 parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
1138                 parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
1139                 ATA_QUEUE_LEN(parm->queue), ATA_QUEUE_LEN(parm->queue));
1140
1141         printf("SMART                          %s       %s\n",
1142                 parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no",
1143                 parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no");
1144
1145         printf("microcode download             %s       %s\n",
1146                 parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no",
1147                 parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no");
1148
1149         printf("security                       %s       %s\n",
1150                 parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no",
1151                 parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no");
1152
1153         printf("power management               %s       %s\n",
1154                 parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no",
1155                 parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no");
1156
1157         printf("advanced power management      %s       %s      %d/0x%02X\n",
1158                 parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no",
1159                 parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no",
1160                 parm->apm_value, parm->apm_value);
1161
1162         printf("automatic acoustic management  %s       %s      "
1163                 "%d/0x%02X      %d/0x%02X\n",
1164                 parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
1165                 parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
1166                 ATA_ACOUSTIC_CURRENT(parm->acoustic),
1167                 ATA_ACOUSTIC_CURRENT(parm->acoustic),
1168                 ATA_ACOUSTIC_VENDOR(parm->acoustic),
1169                 ATA_ACOUSTIC_VENDOR(parm->acoustic));
1170 }
1171
1172
1173 static int
1174 ataidentify(struct cam_device *device, int retry_count, int timeout)
1175 {
1176         union ccb *ccb;
1177         struct ata_params *ident_buf;
1178         struct ccb_getdev cgd;
1179         u_int i, error = 0;
1180         int16_t *ptr;
1181
1182         if (get_cgd(device, &cgd) != 0) {
1183                 warnx("couldn't get CGD");
1184                 return(1);
1185         }
1186         ccb = cam_getccb(device);
1187
1188         if (ccb == NULL) {
1189                 warnx("couldn't allocate CCB");
1190                 return(1);
1191         }
1192
1193         /* cam_getccb cleans up the header, caller has to zero the payload */
1194         bzero(&(&ccb->ccb_h)[1],
1195               sizeof(struct ccb_ataio) - sizeof(struct ccb_hdr));
1196
1197         ptr = (uint16_t *)malloc(sizeof(struct ata_params));
1198
1199         if (ptr == NULL) {
1200                 cam_freeccb(ccb);
1201                 warnx("can't malloc memory for identify\n");
1202                 return(1);
1203         }
1204         bzero(ptr, sizeof(struct ata_params));
1205
1206         cam_fill_ataio(&ccb->ataio,
1207                       retry_count,
1208                       NULL,
1209                       /*flags*/CAM_DIR_IN,
1210                       MSG_SIMPLE_Q_TAG,
1211                       /*data_ptr*/(u_int8_t *)ptr,
1212                       /*dxfer_len*/sizeof(struct ata_params),
1213                       timeout ? timeout : 30 * 1000);
1214         if (cgd.protocol == PROTO_ATA)
1215                 ata_28bit_cmd(&ccb->ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
1216         else
1217                 ata_28bit_cmd(&ccb->ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0);
1218
1219         /* Disable freezing the device queue */
1220         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
1221
1222         if (arglist & CAM_ARG_ERR_RECOVER)
1223                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
1224
1225         if (cam_send_ccb(device, ccb) < 0) {
1226                 perror("error sending ATA identify");
1227
1228                 if (arglist & CAM_ARG_VERBOSE) {
1229                         cam_error_print(device, ccb, CAM_ESF_ALL,
1230                                         CAM_EPF_ALL, stderr);
1231                 }
1232
1233                 free(ptr);
1234                 cam_freeccb(ccb);
1235                 return(1);
1236         }
1237
1238         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1239                 error = 1;
1240
1241                 if (arglist & CAM_ARG_VERBOSE) {
1242                         cam_error_print(device, ccb, CAM_ESF_ALL,
1243                                         CAM_EPF_ALL, stderr);
1244                 }
1245         }
1246
1247         cam_freeccb(ccb);
1248
1249         if (error != 0) {
1250                 free(ptr);
1251                 return(error);
1252         }
1253
1254         for (i = 0; i < sizeof(struct ata_params) / 2; i++)
1255                 ptr[i] = le16toh(ptr[i]);
1256         ident_buf = (struct ata_params *)ptr;
1257
1258         if (strncmp(ident_buf->model, "FX", 2) &&
1259             strncmp(ident_buf->model, "NEC", 3) &&
1260             strncmp(ident_buf->model, "Pioneer", 7) &&
1261             strncmp(ident_buf->model, "SHARP", 5)) {
1262                 ata_bswap(ident_buf->model, sizeof(ident_buf->model));
1263                 ata_bswap(ident_buf->revision, sizeof(ident_buf->revision));
1264                 ata_bswap(ident_buf->serial, sizeof(ident_buf->serial));
1265         }
1266         ata_btrim(ident_buf->model, sizeof(ident_buf->model));
1267         ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model));
1268         ata_btrim(ident_buf->revision, sizeof(ident_buf->revision));
1269         ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision));
1270         ata_btrim(ident_buf->serial, sizeof(ident_buf->serial));
1271         ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial));
1272
1273         fprintf(stdout, "%s%d: ", device->device_name,
1274                 device->dev_unit_num);
1275         ata_print_ident(ident_buf);
1276         atacapprint(ident_buf);
1277
1278         free(ident_buf);
1279
1280         return(0);
1281 }
1282 #endif /* MINIMALISTIC */
1283
1284 /*
1285  * Parse out a bus, or a bus, target and lun in the following
1286  * format:
1287  * bus
1288  * bus:target
1289  * bus:target:lun
1290  *
1291  * Returns the number of parsed components, or 0.
1292  */
1293 static int
1294 parse_btl(char *tstr, int *bus, int *target, int *lun, cam_argmask *arglst)
1295 {
1296         char *tmpstr;
1297         int convs = 0;
1298
1299         while (isspace(*tstr) && (*tstr != '\0'))
1300                 tstr++;
1301
1302         tmpstr = (char *)strtok(tstr, ":");
1303         if ((tmpstr != NULL) && (*tmpstr != '\0')) {
1304                 *bus = strtol(tmpstr, NULL, 0);
1305                 *arglst |= CAM_ARG_BUS;
1306                 convs++;
1307                 tmpstr = (char *)strtok(NULL, ":");
1308                 if ((tmpstr != NULL) && (*tmpstr != '\0')) {
1309                         *target = strtol(tmpstr, NULL, 0);
1310                         *arglst |= CAM_ARG_TARGET;
1311                         convs++;
1312                         tmpstr = (char *)strtok(NULL, ":");
1313                         if ((tmpstr != NULL) && (*tmpstr != '\0')) {
1314                                 *lun = strtol(tmpstr, NULL, 0);
1315                                 *arglst |= CAM_ARG_LUN;
1316                                 convs++;
1317                         }
1318                 }
1319         }
1320
1321         return convs;
1322 }
1323
1324 static int
1325 dorescan_or_reset(int argc, char **argv, int rescan)
1326 {
1327         static const char must[] =
1328                 "you must specify \"all\", a bus, or a bus:target:lun to %s";
1329         int rv, error = 0;
1330         int bus = -1, target = -1, lun = -1;
1331         char *tstr;
1332
1333         if (argc < 3) {
1334                 warnx(must, rescan? "rescan" : "reset");
1335                 return(1);
1336         }
1337
1338         tstr = argv[optind];
1339         while (isspace(*tstr) && (*tstr != '\0'))
1340                 tstr++;
1341         if (strncasecmp(tstr, "all", strlen("all")) == 0)
1342                 arglist |= CAM_ARG_BUS;
1343         else {
1344                 rv = parse_btl(argv[optind], &bus, &target, &lun, &arglist);
1345                 if (rv != 1 && rv != 3) {
1346                         warnx(must, rescan? "rescan" : "reset");
1347                         return(1);
1348                 }
1349         }
1350
1351         if ((arglist & CAM_ARG_BUS)
1352             && (arglist & CAM_ARG_TARGET)
1353             && (arglist & CAM_ARG_LUN))
1354                 error = scanlun_or_reset_dev(bus, target, lun, rescan);
1355         else
1356                 error = rescan_or_reset_bus(bus, rescan);
1357
1358         return(error);
1359 }
1360
1361 static int
1362 rescan_or_reset_bus(int bus, int rescan)
1363 {
1364         union ccb ccb, matchccb;
1365         int fd, retval;
1366         int bufsize;
1367
1368         retval = 0;
1369
1370         if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
1371                 warnx("error opening transport layer device %s", XPT_DEVICE);
1372                 warn("%s", XPT_DEVICE);
1373                 return(1);
1374         }
1375
1376         if (bus != -1) {
1377                 ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS : XPT_RESET_BUS;
1378                 ccb.ccb_h.path_id = bus;
1379                 ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
1380                 ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
1381                 ccb.crcn.flags = CAM_FLAG_NONE;
1382
1383                 /* run this at a low priority */
1384                 ccb.ccb_h.pinfo.priority = 5;
1385
1386                 if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
1387                         warn("CAMIOCOMMAND ioctl failed");
1388                         close(fd);
1389                         return(1);
1390                 }
1391
1392                 if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
1393                         fprintf(stdout, "%s of bus %d was successful\n",
1394                             rescan ? "Re-scan" : "Reset", bus);
1395                 } else {
1396                         fprintf(stdout, "%s of bus %d returned error %#x\n",
1397                                 rescan ? "Re-scan" : "Reset", bus,
1398                                 ccb.ccb_h.status & CAM_STATUS_MASK);
1399                         retval = 1;
1400                 }
1401
1402                 close(fd);
1403                 return(retval);
1404
1405         }
1406
1407
1408         /*
1409          * The right way to handle this is to modify the xpt so that it can
1410          * handle a wildcarded bus in a rescan or reset CCB.  At the moment
1411          * that isn't implemented, so instead we enumerate the busses and
1412          * send the rescan or reset to those busses in the case where the
1413          * given bus is -1 (wildcard).  We don't send a rescan or reset
1414          * to the xpt bus; sending a rescan to the xpt bus is effectively a
1415          * no-op, sending a rescan to the xpt bus would result in a status of
1416          * CAM_REQ_INVALID.
1417          */
1418         bzero(&(&matchccb.ccb_h)[1],
1419               sizeof(struct ccb_dev_match) - sizeof(struct ccb_hdr));
1420         matchccb.ccb_h.func_code = XPT_DEV_MATCH;
1421         bufsize = sizeof(struct dev_match_result) * 20;
1422         matchccb.cdm.match_buf_len = bufsize;
1423         matchccb.cdm.matches=(struct dev_match_result *)malloc(bufsize);
1424         if (matchccb.cdm.matches == NULL) {
1425                 warnx("can't malloc memory for matches");
1426                 retval = 1;
1427                 goto bailout;
1428         }
1429         matchccb.cdm.num_matches = 0;
1430
1431         matchccb.cdm.num_patterns = 1;
1432         matchccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern);
1433
1434         matchccb.cdm.patterns = (struct dev_match_pattern *)malloc(
1435                 matchccb.cdm.pattern_buf_len);
1436         if (matchccb.cdm.patterns == NULL) {
1437                 warnx("can't malloc memory for patterns");
1438                 retval = 1;
1439                 goto bailout;
1440         }
1441         matchccb.cdm.patterns[0].type = DEV_MATCH_BUS;
1442         matchccb.cdm.patterns[0].pattern.bus_pattern.flags = BUS_MATCH_ANY;
1443
1444         do {
1445                 unsigned int i;
1446
1447                 if (ioctl(fd, CAMIOCOMMAND, &matchccb) == -1) {
1448                         warn("CAMIOCOMMAND ioctl failed");
1449                         retval = 1;
1450                         goto bailout;
1451                 }
1452
1453                 if ((matchccb.ccb_h.status != CAM_REQ_CMP)
1454                  || ((matchccb.cdm.status != CAM_DEV_MATCH_LAST)
1455                    && (matchccb.cdm.status != CAM_DEV_MATCH_MORE))) {
1456                         warnx("got CAM error %#x, CDM error %d\n",
1457                               matchccb.ccb_h.status, matchccb.cdm.status);
1458                         retval = 1;
1459                         goto bailout;
1460                 }
1461
1462                 for (i = 0; i < matchccb.cdm.num_matches; i++) {
1463                         struct bus_match_result *bus_result;
1464
1465                         /* This shouldn't happen. */
1466                         if (matchccb.cdm.matches[i].type != DEV_MATCH_BUS)
1467                                 continue;
1468
1469                         bus_result = &matchccb.cdm.matches[i].result.bus_result;
1470
1471                         /*
1472                          * We don't want to rescan or reset the xpt bus.
1473                          * See above.
1474                          */
1475                         if ((int)bus_result->path_id == -1)
1476                                 continue;
1477
1478                         ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS :
1479                                                        XPT_RESET_BUS;
1480                         ccb.ccb_h.path_id = bus_result->path_id;
1481                         ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
1482                         ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
1483                         ccb.crcn.flags = CAM_FLAG_NONE;
1484
1485                         /* run this at a low priority */
1486                         ccb.ccb_h.pinfo.priority = 5;
1487
1488                         if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
1489                                 warn("CAMIOCOMMAND ioctl failed");
1490                                 retval = 1;
1491                                 goto bailout;
1492                         }
1493
1494                         if ((ccb.ccb_h.status & CAM_STATUS_MASK) ==CAM_REQ_CMP){
1495                                 fprintf(stdout, "%s of bus %d was successful\n",
1496                                         rescan? "Re-scan" : "Reset",
1497                                         bus_result->path_id);
1498                         } else {
1499                                 /*
1500                                  * Don't bail out just yet, maybe the other
1501                                  * rescan or reset commands will complete
1502                                  * successfully.
1503                                  */
1504                                 fprintf(stderr, "%s of bus %d returned error "
1505                                         "%#x\n", rescan? "Re-scan" : "Reset",
1506                                         bus_result->path_id,
1507                                         ccb.ccb_h.status & CAM_STATUS_MASK);
1508                                 retval = 1;
1509                         }
1510                 }
1511         } while ((matchccb.ccb_h.status == CAM_REQ_CMP)
1512                  && (matchccb.cdm.status == CAM_DEV_MATCH_MORE));
1513
1514 bailout:
1515
1516         if (fd != -1)
1517                 close(fd);
1518
1519         if (matchccb.cdm.patterns != NULL)
1520                 free(matchccb.cdm.patterns);
1521         if (matchccb.cdm.matches != NULL)
1522                 free(matchccb.cdm.matches);
1523
1524         return(retval);
1525 }
1526
1527 static int
1528 scanlun_or_reset_dev(int bus, int target, int lun, int scan)
1529 {
1530         union ccb ccb;
1531         struct cam_device *device;
1532         int fd;
1533
1534         device = NULL;
1535
1536         if (bus < 0) {
1537                 warnx("invalid bus number %d", bus);
1538                 return(1);
1539         }
1540
1541         if (target < 0) {
1542                 warnx("invalid target number %d", target);
1543                 return(1);
1544         }
1545
1546         if (lun < 0) {
1547                 warnx("invalid lun number %d", lun);
1548                 return(1);
1549         }
1550
1551         fd = -1;
1552
1553         bzero(&ccb, sizeof(union ccb));
1554
1555         if (scan) {
1556                 if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
1557                         warnx("error opening transport layer device %s\n",
1558                             XPT_DEVICE);
1559                         warn("%s", XPT_DEVICE);
1560                         return(1);
1561                 }
1562         } else {
1563                 device = cam_open_btl(bus, target, lun, O_RDWR, NULL);
1564                 if (device == NULL) {
1565                         warnx("%s", cam_errbuf);
1566                         return(1);
1567                 }
1568         }
1569
1570         ccb.ccb_h.func_code = (scan)? XPT_SCAN_LUN : XPT_RESET_DEV;
1571         ccb.ccb_h.path_id = bus;
1572         ccb.ccb_h.target_id = target;
1573         ccb.ccb_h.target_lun = lun;
1574         ccb.ccb_h.timeout = 5000;
1575         ccb.crcn.flags = CAM_FLAG_NONE;
1576
1577         /* run this at a low priority */
1578         ccb.ccb_h.pinfo.priority = 5;
1579
1580         if (scan) {
1581                 if (ioctl(fd, CAMIOCOMMAND, &ccb) < 0) {
1582                         warn("CAMIOCOMMAND ioctl failed");
1583                         close(fd);
1584                         return(1);
1585                 }
1586         } else {
1587                 if (cam_send_ccb(device, &ccb) < 0) {
1588                         warn("error sending XPT_RESET_DEV CCB");
1589                         cam_close_device(device);
1590                         return(1);
1591                 }
1592         }
1593
1594         if (scan)
1595                 close(fd);
1596         else
1597                 cam_close_device(device);
1598
1599         /*
1600          * An error code of CAM_BDR_SENT is normal for a BDR request.
1601          */
1602         if (((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
1603          || ((!scan)
1604           && ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_BDR_SENT))) {
1605                 fprintf(stdout, "%s of %d:%d:%d was successful\n",
1606                     scan? "Re-scan" : "Reset", bus, target, lun);
1607                 return(0);
1608         } else {
1609                 fprintf(stdout, "%s of %d:%d:%d returned error %#x\n",
1610                     scan? "Re-scan" : "Reset", bus, target, lun,
1611                     ccb.ccb_h.status & CAM_STATUS_MASK);
1612                 return(1);
1613         }
1614 }
1615
1616 #ifndef MINIMALISTIC
1617 static int
1618 readdefects(struct cam_device *device, int argc, char **argv,
1619             char *combinedopt, int retry_count, int timeout)
1620 {
1621         union ccb *ccb = NULL;
1622         struct scsi_read_defect_data_10 *rdd_cdb;
1623         u_int8_t *defect_list = NULL;
1624         u_int32_t dlist_length = 65000;
1625         u_int32_t returned_length = 0;
1626         u_int32_t num_returned = 0;
1627         u_int8_t returned_format;
1628         unsigned int i;
1629         int c, error = 0;
1630         int lists_specified = 0;
1631
1632         while ((c = getopt(argc, argv, combinedopt)) != -1) {
1633                 switch(c){
1634                 case 'f':
1635                 {
1636                         char *tstr;
1637                         tstr = optarg;
1638                         while (isspace(*tstr) && (*tstr != '\0'))
1639                                 tstr++;
1640                         if (strcmp(tstr, "block") == 0)
1641                                 arglist |= CAM_ARG_FORMAT_BLOCK;
1642                         else if (strcmp(tstr, "bfi") == 0)
1643                                 arglist |= CAM_ARG_FORMAT_BFI;
1644                         else if (strcmp(tstr, "phys") == 0)
1645                                 arglist |= CAM_ARG_FORMAT_PHYS;
1646                         else {
1647                                 error = 1;
1648                                 warnx("invalid defect format %s", tstr);
1649                                 goto defect_bailout;
1650                         }
1651                         break;
1652                 }
1653                 case 'G':
1654                         arglist |= CAM_ARG_GLIST;
1655                         break;
1656                 case 'P':
1657                         arglist |= CAM_ARG_PLIST;
1658                         break;
1659                 default:
1660                         break;
1661                 }
1662         }
1663
1664         ccb = cam_getccb(device);
1665
1666         /*
1667          * Hopefully 65000 bytes is enough to hold the defect list.  If it
1668          * isn't, the disk is probably dead already.  We'd have to go with
1669          * 12 byte command (i.e. alloc_length is 32 bits instead of 16)
1670          * to hold them all.
1671          */
1672         defect_list = malloc(dlist_length);
1673         if (defect_list == NULL) {
1674                 warnx("can't malloc memory for defect list");
1675                 error = 1;
1676                 goto defect_bailout;
1677         }
1678
1679         rdd_cdb =(struct scsi_read_defect_data_10 *)&ccb->csio.cdb_io.cdb_bytes;
1680
1681         /*
1682          * cam_getccb() zeros the CCB header only.  So we need to zero the
1683          * payload portion of the ccb.
1684          */
1685         bzero(&(&ccb->ccb_h)[1],
1686               sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
1687
1688         cam_fill_csio(&ccb->csio,
1689                       /*retries*/ retry_count,
1690                       /*cbfcnp*/ NULL,
1691                       /*flags*/ CAM_DIR_IN | ((arglist & CAM_ARG_ERR_RECOVER) ?
1692                                               CAM_PASS_ERR_RECOVER : 0),
1693                       /*tag_action*/ MSG_SIMPLE_Q_TAG,
1694                       /*data_ptr*/ defect_list,
1695                       /*dxfer_len*/ dlist_length,
1696                       /*sense_len*/ SSD_FULL_SIZE,
1697                       /*cdb_len*/ sizeof(struct scsi_read_defect_data_10),
1698                       /*timeout*/ timeout ? timeout : 5000);
1699
1700         rdd_cdb->opcode = READ_DEFECT_DATA_10;
1701         if (arglist & CAM_ARG_FORMAT_BLOCK)
1702                 rdd_cdb->format = SRDD10_BLOCK_FORMAT;
1703         else if (arglist & CAM_ARG_FORMAT_BFI)
1704                 rdd_cdb->format = SRDD10_BYTES_FROM_INDEX_FORMAT;
1705         else if (arglist & CAM_ARG_FORMAT_PHYS)
1706                 rdd_cdb->format = SRDD10_PHYSICAL_SECTOR_FORMAT;
1707         else {
1708                 error = 1;
1709                 warnx("no defect list format specified");
1710                 goto defect_bailout;
1711         }
1712         if (arglist & CAM_ARG_PLIST) {
1713                 rdd_cdb->format |= SRDD10_PLIST;
1714                 lists_specified++;
1715         }
1716
1717         if (arglist & CAM_ARG_GLIST) {
1718                 rdd_cdb->format |= SRDD10_GLIST;
1719                 lists_specified++;
1720         }
1721
1722         scsi_ulto2b(dlist_length, rdd_cdb->alloc_length);
1723
1724         /* Disable freezing the device queue */
1725         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
1726
1727         if (cam_send_ccb(device, ccb) < 0) {
1728                 perror("error reading defect list");
1729
1730                 if (arglist & CAM_ARG_VERBOSE) {
1731                         cam_error_print(device, ccb, CAM_ESF_ALL,
1732                                         CAM_EPF_ALL, stderr);
1733                 }
1734
1735                 error = 1;
1736                 goto defect_bailout;
1737         }
1738
1739         returned_length = scsi_2btoul(((struct
1740                 scsi_read_defect_data_hdr_10 *)defect_list)->length);
1741
1742         returned_format = ((struct scsi_read_defect_data_hdr_10 *)
1743                         defect_list)->format;
1744
1745         if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR)
1746          && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
1747          && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) {
1748                 struct scsi_sense_data *sense;
1749                 int error_code, sense_key, asc, ascq;
1750
1751                 sense = &ccb->csio.sense_data;
1752                 scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq);
1753
1754                 /*
1755                  * According to the SCSI spec, if the disk doesn't support
1756                  * the requested format, it will generally return a sense
1757                  * key of RECOVERED ERROR, and an additional sense code
1758                  * of "DEFECT LIST NOT FOUND".  So, we check for that, and
1759                  * also check to make sure that the returned length is
1760                  * greater than 0, and then print out whatever format the
1761                  * disk gave us.
1762                  */
1763                 if ((sense_key == SSD_KEY_RECOVERED_ERROR)
1764                  && (asc == 0x1c) && (ascq == 0x00)
1765                  && (returned_length > 0)) {
1766                         warnx("requested defect format not available");
1767                         switch(returned_format & SRDDH10_DLIST_FORMAT_MASK) {
1768                         case SRDD10_BLOCK_FORMAT:
1769                                 warnx("Device returned block format");
1770                                 break;
1771                         case SRDD10_BYTES_FROM_INDEX_FORMAT:
1772                                 warnx("Device returned bytes from index"
1773                                       " format");
1774                                 break;
1775                         case SRDD10_PHYSICAL_SECTOR_FORMAT:
1776                                 warnx("Device returned physical sector format");
1777                                 break;
1778                         default:
1779                                 error = 1;
1780                                 warnx("Device returned unknown defect"
1781                                      " data format %#x", returned_format);
1782                                 goto defect_bailout;
1783                                 break; /* NOTREACHED */
1784                         }
1785                 } else {
1786                         error = 1;
1787                         warnx("Error returned from read defect data command");
1788                         if (arglist & CAM_ARG_VERBOSE)
1789                                 cam_error_print(device, ccb, CAM_ESF_ALL,
1790                                                 CAM_EPF_ALL, stderr);
1791                         goto defect_bailout;
1792                 }
1793         } else if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1794                 error = 1;
1795                 warnx("Error returned from read defect data command");
1796                 if (arglist & CAM_ARG_VERBOSE)
1797                         cam_error_print(device, ccb, CAM_ESF_ALL,
1798                                         CAM_EPF_ALL, stderr);
1799                 goto defect_bailout;
1800         }
1801
1802         /*
1803          * XXX KDM  I should probably clean up the printout format for the
1804          * disk defects. 
1805          */
1806         switch (returned_format & SRDDH10_DLIST_FORMAT_MASK){
1807                 case SRDDH10_PHYSICAL_SECTOR_FORMAT:
1808                 {
1809                         struct scsi_defect_desc_phys_sector *dlist;
1810
1811                         dlist = (struct scsi_defect_desc_phys_sector *)
1812                                 (defect_list +
1813                                 sizeof(struct scsi_read_defect_data_hdr_10));
1814
1815                         num_returned = returned_length /
1816                                 sizeof(struct scsi_defect_desc_phys_sector);
1817
1818                         fprintf(stderr, "Got %d defect", num_returned);
1819
1820                         if ((lists_specified == 0) || (num_returned == 0)) {
1821                                 fprintf(stderr, "s.\n");
1822                                 break;
1823                         } else if (num_returned == 1)
1824                                 fprintf(stderr, ":\n");
1825                         else
1826                                 fprintf(stderr, "s:\n");
1827
1828                         for (i = 0; i < num_returned; i++) {
1829                                 fprintf(stdout, "%d:%d:%d\n",
1830                                         scsi_3btoul(dlist[i].cylinder),
1831                                         dlist[i].head,
1832                                         scsi_4btoul(dlist[i].sector));
1833                         }
1834                         break;
1835                 }
1836                 case SRDDH10_BYTES_FROM_INDEX_FORMAT:
1837                 {
1838                         struct scsi_defect_desc_bytes_from_index *dlist;
1839
1840                         dlist = (struct scsi_defect_desc_bytes_from_index *)
1841                                 (defect_list +
1842                                 sizeof(struct scsi_read_defect_data_hdr_10));
1843
1844                         num_returned = returned_length /
1845                               sizeof(struct scsi_defect_desc_bytes_from_index);
1846
1847                         fprintf(stderr, "Got %d defect", num_returned);
1848
1849                         if ((lists_specified == 0) || (num_returned == 0)) {
1850                                 fprintf(stderr, "s.\n");
1851                                 break;
1852                         } else if (num_returned == 1)
1853                                 fprintf(stderr, ":\n");
1854                         else
1855                                 fprintf(stderr, "s:\n");
1856
1857                         for (i = 0; i < num_returned; i++) {
1858                                 fprintf(stdout, "%d:%d:%d\n",
1859                                         scsi_3btoul(dlist[i].cylinder),
1860                                         dlist[i].head,
1861                                         scsi_4btoul(dlist[i].bytes_from_index));
1862                         }
1863                         break;
1864                 }
1865                 case SRDDH10_BLOCK_FORMAT:
1866                 {
1867                         struct scsi_defect_desc_block *dlist;
1868
1869                         dlist = (struct scsi_defect_desc_block *)(defect_list +
1870                                 sizeof(struct scsi_read_defect_data_hdr_10));
1871
1872                         num_returned = returned_length /
1873                               sizeof(struct scsi_defect_desc_block);
1874
1875                         fprintf(stderr, "Got %d defect", num_returned);
1876
1877                         if ((lists_specified == 0) || (num_returned == 0)) {
1878                                 fprintf(stderr, "s.\n");
1879                                 break;
1880                         } else if (num_returned == 1)
1881                                 fprintf(stderr, ":\n");
1882                         else
1883                                 fprintf(stderr, "s:\n");
1884
1885                         for (i = 0; i < num_returned; i++)
1886                                 fprintf(stdout, "%u\n",
1887                                         scsi_4btoul(dlist[i].address));
1888                         break;
1889                 }
1890                 default:
1891                         fprintf(stderr, "Unknown defect format %d\n",
1892                                 returned_format & SRDDH10_DLIST_FORMAT_MASK);
1893                         error = 1;
1894                         break;
1895         }
1896 defect_bailout:
1897
1898         if (defect_list != NULL)
1899                 free(defect_list);
1900
1901         if (ccb != NULL)
1902                 cam_freeccb(ccb);
1903
1904         return(error);
1905 }
1906 #endif /* MINIMALISTIC */
1907
1908 #if 0
1909 void
1910 reassignblocks(struct cam_device *device, u_int32_t *blocks, int num_blocks)
1911 {
1912         union ccb *ccb;
1913         
1914         ccb = cam_getccb(device);
1915
1916         cam_freeccb(ccb);
1917 }
1918 #endif
1919
1920 #ifndef MINIMALISTIC
1921 void
1922 mode_sense(struct cam_device *device, int mode_page, int page_control,
1923            int dbd, int retry_count, int timeout, u_int8_t *data, int datalen)
1924 {
1925         union ccb *ccb;
1926         int retval;
1927
1928         ccb = cam_getccb(device);
1929
1930         if (ccb == NULL)
1931                 errx(1, "mode_sense: couldn't allocate CCB");
1932
1933         bzero(&(&ccb->ccb_h)[1],
1934               sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
1935
1936         scsi_mode_sense(&ccb->csio,
1937                         /* retries */ retry_count,
1938                         /* cbfcnp */ NULL,
1939                         /* tag_action */ MSG_SIMPLE_Q_TAG,
1940                         /* dbd */ dbd,
1941                         /* page_code */ page_control << 6,
1942                         /* page */ mode_page,
1943                         /* param_buf */ data,
1944                         /* param_len */ datalen,
1945                         /* sense_len */ SSD_FULL_SIZE,
1946                         /* timeout */ timeout ? timeout : 5000);
1947
1948         if (arglist & CAM_ARG_ERR_RECOVER)
1949                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
1950
1951         /* Disable freezing the device queue */
1952         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
1953
1954         if (((retval = cam_send_ccb(device, ccb)) < 0)
1955          || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
1956                 if (arglist & CAM_ARG_VERBOSE) {
1957                         cam_error_print(device, ccb, CAM_ESF_ALL,
1958                                         CAM_EPF_ALL, stderr);
1959                 }
1960                 cam_freeccb(ccb);
1961                 cam_close_device(device);
1962                 if (retval < 0)
1963                         err(1, "error sending mode sense command");
1964                 else
1965                         errx(1, "error sending mode sense command");
1966         }
1967
1968         cam_freeccb(ccb);
1969 }
1970
1971 void
1972 mode_select(struct cam_device *device, int save_pages, int retry_count,
1973            int timeout, u_int8_t *data, int datalen)
1974 {
1975         union ccb *ccb;
1976         int retval;
1977
1978         ccb = cam_getccb(device);
1979
1980         if (ccb == NULL)
1981                 errx(1, "mode_select: couldn't allocate CCB");
1982
1983         bzero(&(&ccb->ccb_h)[1],
1984               sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
1985
1986         scsi_mode_select(&ccb->csio,
1987                          /* retries */ retry_count,
1988                          /* cbfcnp */ NULL,
1989                          /* tag_action */ MSG_SIMPLE_Q_TAG,
1990                          /* scsi_page_fmt */ 1,
1991                          /* save_pages */ save_pages,
1992                          /* param_buf */ data,
1993                          /* param_len */ datalen,
1994                          /* sense_len */ SSD_FULL_SIZE,
1995                          /* timeout */ timeout ? timeout : 5000);
1996
1997         if (arglist & CAM_ARG_ERR_RECOVER)
1998                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
1999
2000         /* Disable freezing the device queue */
2001         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
2002
2003         if (((retval = cam_send_ccb(device, ccb)) < 0)
2004          || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
2005                 if (arglist & CAM_ARG_VERBOSE) {
2006                         cam_error_print(device, ccb, CAM_ESF_ALL,
2007                                         CAM_EPF_ALL, stderr);
2008                 }
2009                 cam_freeccb(ccb);
2010                 cam_close_device(device);
2011
2012                 if (retval < 0)
2013                         err(1, "error sending mode select command");
2014                 else
2015                         errx(1, "error sending mode select command");
2016                 
2017         }
2018
2019         cam_freeccb(ccb);
2020 }
2021
2022 void
2023 modepage(struct cam_device *device, int argc, char **argv, char *combinedopt,
2024          int retry_count, int timeout)
2025 {
2026         int c, mode_page = -1, page_control = 0;
2027         int binary = 0, list = 0;
2028
2029         while ((c = getopt(argc, argv, combinedopt)) != -1) {
2030                 switch(c) {
2031                 case 'b':
2032                         binary = 1;
2033                         break;
2034                 case 'd':
2035                         arglist |= CAM_ARG_DBD;
2036                         break;
2037                 case 'e':
2038                         arglist |= CAM_ARG_MODE_EDIT;
2039                         break;
2040                 case 'l':
2041                         list = 1;
2042                         break;
2043                 case 'm':
2044                         mode_page = strtol(optarg, NULL, 0);
2045                         if (mode_page < 0)
2046                                 errx(1, "invalid mode page %d", mode_page);
2047                         break;
2048                 case 'P':
2049                         page_control = strtol(optarg, NULL, 0);
2050                         if ((page_control < 0) || (page_control > 3))
2051                                 errx(1, "invalid page control field %d",
2052                                      page_control);
2053                         arglist |= CAM_ARG_PAGE_CNTL;
2054                         break;
2055                 default:
2056                         break;
2057                 }
2058         }
2059
2060         if (mode_page == -1 && list == 0)
2061                 errx(1, "you must specify a mode page!");
2062
2063         if (list) {
2064                 mode_list(device, page_control, arglist & CAM_ARG_DBD,
2065                     retry_count, timeout);
2066         } else {
2067                 mode_edit(device, mode_page, page_control,
2068                     arglist & CAM_ARG_DBD, arglist & CAM_ARG_MODE_EDIT, binary,
2069                     retry_count, timeout);
2070         }
2071 }
2072
2073 static int
2074 scsicmd(struct cam_device *device, int argc, char **argv, char *combinedopt,
2075         int retry_count, int timeout)
2076 {
2077         union ccb *ccb;
2078         u_int32_t flags = CAM_DIR_NONE;
2079         u_int8_t *data_ptr = NULL;
2080         u_int8_t cdb[20];
2081         struct get_hook hook;
2082         int c, data_bytes = 0;
2083         int cdb_len = 0;
2084         char *datastr = NULL, *tstr;
2085         int error = 0;
2086         int fd_data = 0;
2087         int retval;
2088
2089         ccb = cam_getccb(device);
2090
2091         if (ccb == NULL) {
2092                 warnx("scsicmd: error allocating ccb");
2093                 return(1);
2094         }
2095
2096         bzero(&(&ccb->ccb_h)[1],
2097               sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
2098
2099         while ((c = getopt(argc, argv, combinedopt)) != -1) {
2100                 switch(c) {
2101                 case 'c':
2102                         tstr = optarg;
2103                         while (isspace(*tstr) && (*tstr != '\0'))
2104                                 tstr++;
2105                         hook.argc = argc - optind;
2106                         hook.argv = argv + optind;
2107                         hook.got = 0;
2108                         cdb_len = buff_encode_visit(cdb, sizeof(cdb), tstr,
2109                                                     iget, &hook);
2110                         /*
2111                          * Increment optind by the number of arguments the
2112                          * encoding routine processed.  After each call to
2113                          * getopt(3), optind points to the argument that
2114                          * getopt should process _next_.  In this case,
2115                          * that means it points to the first command string
2116                          * argument, if there is one.  Once we increment
2117                          * this, it should point to either the next command
2118                          * line argument, or it should be past the end of
2119                          * the list.
2120                          */
2121                         optind += hook.got;
2122                         break;
2123                 case 'i':
2124                         if (arglist & CAM_ARG_CMD_OUT) {
2125                                 warnx("command must either be "
2126                                       "read or write, not both");
2127                                 error = 1;
2128                                 goto scsicmd_bailout;
2129                         }
2130                         arglist |= CAM_ARG_CMD_IN;
2131                         flags = CAM_DIR_IN;
2132                         data_bytes = strtol(optarg, NULL, 0);
2133                         if (data_bytes <= 0) {
2134                                 warnx("invalid number of input bytes %d",
2135                                       data_bytes);
2136                                 error = 1;
2137                                 goto scsicmd_bailout;
2138                         }
2139                         hook.argc = argc - optind;
2140                         hook.argv = argv + optind;
2141                         hook.got = 0;
2142                         optind++;
2143                         datastr = cget(&hook, NULL);
2144                         /*
2145                          * If the user supplied "-" instead of a format, he
2146                          * wants the data to be written to stdout.
2147                          */
2148                         if ((datastr != NULL)
2149                          && (datastr[0] == '-'))
2150                                 fd_data = 1;
2151
2152                         data_ptr = (u_int8_t *)malloc(data_bytes);
2153                         if (data_ptr == NULL) {
2154                                 warnx("can't malloc memory for data_ptr");
2155                                 error = 1;
2156                                 goto scsicmd_bailout;
2157                         }
2158                         break;
2159                 case 'o':
2160                         if (arglist & CAM_ARG_CMD_IN) {
2161                                 warnx("command must either be "
2162                                       "read or write, not both");
2163                                 error = 1;      
2164                                 goto scsicmd_bailout;
2165                         }
2166                         arglist |= CAM_ARG_CMD_OUT;
2167                         flags = CAM_DIR_OUT;
2168                         data_bytes = strtol(optarg, NULL, 0);
2169                         if (data_bytes <= 0) {
2170                                 warnx("invalid number of output bytes %d",
2171                                       data_bytes);
2172                                 error = 1;
2173                                 goto scsicmd_bailout;
2174                         }
2175                         hook.argc = argc - optind;
2176                         hook.argv = argv + optind;
2177                         hook.got = 0;
2178                         datastr = cget(&hook, NULL);
2179                         data_ptr = (u_int8_t *)malloc(data_bytes);
2180                         if (data_ptr == NULL) {
2181                                 warnx("can't malloc memory for data_ptr");
2182                                 error = 1;
2183                                 goto scsicmd_bailout;
2184                         }
2185                         /*
2186                          * If the user supplied "-" instead of a format, he
2187                          * wants the data to be read from stdin.
2188                          */
2189                         if ((datastr != NULL)
2190                          && (datastr[0] == '-'))
2191                                 fd_data = 1;
2192                         else
2193                                 buff_encode_visit(data_ptr, data_bytes, datastr,
2194                                                   iget, &hook);
2195                         optind += hook.got;
2196                         break;
2197                 default:
2198                         break;
2199                 }
2200         }
2201
2202         /*
2203          * If fd_data is set, and we're writing to the device, we need to
2204          * read the data the user wants written from stdin.
2205          */
2206         if ((fd_data == 1) && (arglist & CAM_ARG_CMD_OUT)) {
2207                 ssize_t amt_read;
2208                 int amt_to_read = data_bytes;
2209                 u_int8_t *buf_ptr = data_ptr;
2210
2211                 for (amt_read = 0; amt_to_read > 0;
2212                      amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) {
2213                         if (amt_read == -1) {
2214                                 warn("error reading data from stdin");
2215                                 error = 1;
2216                                 goto scsicmd_bailout;
2217                         }
2218                         amt_to_read -= amt_read;
2219                         buf_ptr += amt_read;
2220                 }
2221         }
2222
2223         if (arglist & CAM_ARG_ERR_RECOVER)
2224                 flags |= CAM_PASS_ERR_RECOVER;
2225
2226         /* Disable freezing the device queue */
2227         flags |= CAM_DEV_QFRZDIS;
2228
2229         /*
2230          * This is taken from the SCSI-3 draft spec.
2231          * (T10/1157D revision 0.3)
2232          * The top 3 bits of an opcode are the group code.  The next 5 bits
2233          * are the command code.
2234          * Group 0:  six byte commands
2235          * Group 1:  ten byte commands
2236          * Group 2:  ten byte commands
2237          * Group 3:  reserved
2238          * Group 4:  sixteen byte commands
2239          * Group 5:  twelve byte commands
2240          * Group 6:  vendor specific
2241          * Group 7:  vendor specific
2242          */
2243         switch((cdb[0] >> 5) & 0x7) {
2244                 case 0:
2245                         cdb_len = 6;
2246                         break;
2247                 case 1:
2248                 case 2:
2249                         cdb_len = 10;
2250                         break;
2251                 case 3:
2252                 case 6:
2253                 case 7:
2254                         /* computed by buff_encode_visit */
2255                         break;
2256                 case 4:
2257                         cdb_len = 16;
2258                         break;
2259                 case 5:
2260                         cdb_len = 12;
2261                         break;
2262         }
2263
2264         /*
2265          * We should probably use csio_build_visit or something like that
2266          * here, but it's easier to encode arguments as you go.  The
2267          * alternative would be skipping the CDB argument and then encoding
2268          * it here, since we've got the data buffer argument by now.
2269          */
2270         bcopy(cdb, &ccb->csio.cdb_io.cdb_bytes, cdb_len);
2271
2272         cam_fill_csio(&ccb->csio,
2273                       /*retries*/ retry_count,
2274                       /*cbfcnp*/ NULL,
2275                       /*flags*/ flags,
2276                       /*tag_action*/ MSG_SIMPLE_Q_TAG,
2277                       /*data_ptr*/ data_ptr,
2278                       /*dxfer_len*/ data_bytes,
2279                       /*sense_len*/ SSD_FULL_SIZE,
2280                       /*cdb_len*/ cdb_len,
2281                       /*timeout*/ timeout ? timeout : 5000);
2282
2283         if (((retval = cam_send_ccb(device, ccb)) < 0)
2284          || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
2285                 if (retval < 0)
2286                         warn("error sending command");
2287                 else
2288                         warnx("error sending command");
2289
2290                 if (arglist & CAM_ARG_VERBOSE) {
2291                         cam_error_print(device, ccb, CAM_ESF_ALL,
2292                                         CAM_EPF_ALL, stderr);
2293                 }
2294
2295                 error = 1;
2296                 goto scsicmd_bailout;
2297         }
2298
2299
2300         if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
2301          && (arglist & CAM_ARG_CMD_IN)
2302          && (data_bytes > 0)) {
2303                 if (fd_data == 0) {
2304                         buff_decode_visit(data_ptr, data_bytes, datastr,
2305                                           arg_put, NULL);
2306                         fprintf(stdout, "\n");
2307                 } else {
2308                         ssize_t amt_written;
2309                         int amt_to_write = data_bytes;
2310                         u_int8_t *buf_ptr = data_ptr;
2311
2312                         for (amt_written = 0; (amt_to_write > 0) &&
2313                              (amt_written =write(1, buf_ptr,amt_to_write))> 0;){
2314                                 amt_to_write -= amt_written;
2315                                 buf_ptr += amt_written;
2316                         }
2317                         if (amt_written == -1) {
2318                                 warn("error writing data to stdout");
2319                                 error = 1;
2320                                 goto scsicmd_bailout;
2321                         } else if ((amt_written == 0)
2322                                 && (amt_to_write > 0)) {
2323                                 warnx("only wrote %u bytes out of %u",
2324                                       data_bytes - amt_to_write, data_bytes);
2325                         }
2326                 }
2327         }
2328
2329 scsicmd_bailout:
2330
2331         if ((data_bytes > 0) && (data_ptr != NULL))
2332                 free(data_ptr);
2333
2334         cam_freeccb(ccb);
2335
2336         return(error);
2337 }
2338
2339 static int
2340 camdebug(int argc, char **argv, char *combinedopt)
2341 {
2342         int c, fd;
2343         int bus = -1, target = -1, lun = -1;
2344         char *tstr, *tmpstr = NULL;
2345         union ccb ccb;
2346         int error = 0;
2347
2348         bzero(&ccb, sizeof(union ccb));
2349
2350         while ((c = getopt(argc, argv, combinedopt)) != -1) {
2351                 switch(c) {
2352                 case 'I':
2353                         arglist |= CAM_ARG_DEBUG_INFO;
2354                         ccb.cdbg.flags |= CAM_DEBUG_INFO;
2355                         break;
2356                 case 'P':
2357                         arglist |= CAM_ARG_DEBUG_PERIPH;
2358                         ccb.cdbg.flags |= CAM_DEBUG_PERIPH;
2359                         break;
2360                 case 'S':
2361                         arglist |= CAM_ARG_DEBUG_SUBTRACE;
2362                         ccb.cdbg.flags |= CAM_DEBUG_SUBTRACE;
2363                         break;
2364                 case 'T':
2365                         arglist |= CAM_ARG_DEBUG_TRACE;
2366                         ccb.cdbg.flags |= CAM_DEBUG_TRACE;
2367                         break;
2368                 case 'X':
2369                         arglist |= CAM_ARG_DEBUG_XPT;
2370                         ccb.cdbg.flags |= CAM_DEBUG_XPT;
2371                         break;
2372                 case 'c':
2373                         arglist |= CAM_ARG_DEBUG_CDB;
2374                         ccb.cdbg.flags |= CAM_DEBUG_CDB;
2375                         break;
2376                 default:
2377                         break;
2378                 }
2379         }
2380
2381         if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
2382                 warnx("error opening transport layer device %s", XPT_DEVICE);
2383                 warn("%s", XPT_DEVICE);
2384                 return(1);
2385         }
2386         argc -= optind;
2387         argv += optind;
2388
2389         if (argc <= 0) {
2390                 warnx("you must specify \"off\", \"all\" or a bus,");
2391                 warnx("bus:target, or bus:target:lun");
2392                 close(fd);
2393                 return(1);
2394         }
2395
2396         tstr = *argv;
2397
2398         while (isspace(*tstr) && (*tstr != '\0'))
2399                 tstr++;
2400
2401         if (strncmp(tstr, "off", 3) == 0) {
2402                 ccb.cdbg.flags = CAM_DEBUG_NONE;
2403                 arglist &= ~(CAM_ARG_DEBUG_INFO|CAM_ARG_DEBUG_PERIPH|
2404                              CAM_ARG_DEBUG_TRACE|CAM_ARG_DEBUG_SUBTRACE|
2405                              CAM_ARG_DEBUG_XPT);
2406         } else if (strncmp(tstr, "all", 3) != 0) {
2407                 tmpstr = (char *)strtok(tstr, ":");
2408                 if ((tmpstr != NULL) && (*tmpstr != '\0')){
2409                         bus = strtol(tmpstr, NULL, 0);
2410                         arglist |= CAM_ARG_BUS;
2411                         tmpstr = (char *)strtok(NULL, ":");
2412                         if ((tmpstr != NULL) && (*tmpstr != '\0')){
2413                                 target = strtol(tmpstr, NULL, 0);
2414                                 arglist |= CAM_ARG_TARGET;
2415                                 tmpstr = (char *)strtok(NULL, ":");
2416                                 if ((tmpstr != NULL) && (*tmpstr != '\0')){
2417                                         lun = strtol(tmpstr, NULL, 0);
2418                                         arglist |= CAM_ARG_LUN;
2419                                 }
2420                         }
2421                 } else {
2422                         error = 1;
2423                         warnx("you must specify \"all\", \"off\", or a bus,");
2424                         warnx("bus:target, or bus:target:lun to debug");
2425                 }
2426         }
2427         
2428         if (error == 0) {
2429
2430                 ccb.ccb_h.func_code = XPT_DEBUG;
2431                 ccb.ccb_h.path_id = bus;
2432                 ccb.ccb_h.target_id = target;
2433                 ccb.ccb_h.target_lun = lun;
2434
2435                 if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
2436                         warn("CAMIOCOMMAND ioctl failed");
2437                         error = 1;
2438                 }
2439
2440                 if (error == 0) {
2441                         if ((ccb.ccb_h.status & CAM_STATUS_MASK) ==
2442                              CAM_FUNC_NOTAVAIL) {
2443                                 warnx("CAM debugging not available");
2444                                 warnx("you need to put options CAMDEBUG in"
2445                                       " your kernel config file!");
2446                                 error = 1;
2447                         } else if ((ccb.ccb_h.status & CAM_STATUS_MASK) !=
2448                                     CAM_REQ_CMP) {
2449                                 warnx("XPT_DEBUG CCB failed with status %#x",
2450                                       ccb.ccb_h.status);
2451                                 error = 1;
2452                         } else {
2453                                 if (ccb.cdbg.flags == CAM_DEBUG_NONE) {
2454                                         fprintf(stderr,
2455                                                 "Debugging turned off\n");
2456                                 } else {
2457                                         fprintf(stderr,
2458                                                 "Debugging enabled for "
2459                                                 "%d:%d:%d\n",
2460                                                 bus, target, lun);
2461                                 }
2462                         }
2463                 }
2464                 close(fd);
2465         }
2466
2467         return(error);
2468 }
2469
2470 static int
2471 tagcontrol(struct cam_device *device, int argc, char **argv,
2472            char *combinedopt)
2473 {
2474         int c;
2475         union ccb *ccb;
2476         int numtags = -1;
2477         int retval = 0;
2478         int quiet = 0;
2479         char pathstr[1024];
2480
2481         ccb = cam_getccb(device);
2482
2483         if (ccb == NULL) {
2484                 warnx("tagcontrol: error allocating ccb");
2485                 return(1);
2486         }
2487
2488         while ((c = getopt(argc, argv, combinedopt)) != -1) {
2489                 switch(c) {
2490                 case 'N':
2491                         numtags = strtol(optarg, NULL, 0);
2492                         if (numtags < 0) {
2493                                 warnx("tag count %d is < 0", numtags);
2494                                 retval = 1;
2495                                 goto tagcontrol_bailout;
2496                         }
2497                         break;
2498                 case 'q':
2499                         quiet++;
2500                         break;
2501                 default:
2502                         break;
2503                 }
2504         }
2505
2506         cam_path_string(device, pathstr, sizeof(pathstr));
2507
2508         if (numtags >= 0) {
2509                 bzero(&(&ccb->ccb_h)[1],
2510                       sizeof(struct ccb_relsim) - sizeof(struct ccb_hdr));
2511                 ccb->ccb_h.func_code = XPT_REL_SIMQ;
2512                 ccb->crs.release_flags = RELSIM_ADJUST_OPENINGS;
2513                 ccb->crs.openings = numtags;
2514
2515
2516                 if (cam_send_ccb(device, ccb) < 0) {
2517                         perror("error sending XPT_REL_SIMQ CCB");
2518                         retval = 1;
2519                         goto tagcontrol_bailout;
2520                 }
2521
2522                 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2523                         warnx("XPT_REL_SIMQ CCB failed");
2524                         cam_error_print(device, ccb, CAM_ESF_ALL,
2525                                         CAM_EPF_ALL, stderr);
2526                         retval = 1;
2527                         goto tagcontrol_bailout;
2528                 }
2529
2530
2531                 if (quiet == 0)
2532                         fprintf(stdout, "%stagged openings now %d\n",
2533                                 pathstr, ccb->crs.openings);
2534         }
2535
2536         bzero(&(&ccb->ccb_h)[1],
2537               sizeof(struct ccb_getdevstats) - sizeof(struct ccb_hdr));
2538
2539         ccb->ccb_h.func_code = XPT_GDEV_STATS;
2540
2541         if (cam_send_ccb(device, ccb) < 0) {
2542                 perror("error sending XPT_GDEV_STATS CCB");
2543                 retval = 1;
2544                 goto tagcontrol_bailout;
2545         }
2546
2547         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2548                 warnx("XPT_GDEV_STATS CCB failed");
2549                 cam_error_print(device, ccb, CAM_ESF_ALL,
2550                                 CAM_EPF_ALL, stderr);
2551                 retval = 1;
2552                 goto tagcontrol_bailout;
2553         }
2554
2555         if (arglist & CAM_ARG_VERBOSE) {
2556                 fprintf(stdout, "%s", pathstr);
2557                 fprintf(stdout, "dev_openings  %d\n", ccb->cgds.dev_openings);
2558                 fprintf(stdout, "%s", pathstr);
2559                 fprintf(stdout, "dev_active    %d\n", ccb->cgds.dev_active);
2560                 fprintf(stdout, "%s", pathstr);
2561                 fprintf(stdout, "devq_openings %d\n", ccb->cgds.devq_openings);
2562                 fprintf(stdout, "%s", pathstr);
2563                 fprintf(stdout, "devq_queued   %d\n", ccb->cgds.devq_queued);
2564                 fprintf(stdout, "%s", pathstr);
2565                 fprintf(stdout, "held          %d\n", ccb->cgds.held);
2566                 fprintf(stdout, "%s", pathstr);
2567                 fprintf(stdout, "mintags       %d\n", ccb->cgds.mintags);
2568                 fprintf(stdout, "%s", pathstr);
2569                 fprintf(stdout, "maxtags       %d\n", ccb->cgds.maxtags);
2570         } else {
2571                 if (quiet == 0) {
2572                         fprintf(stdout, "%s", pathstr);
2573                         fprintf(stdout, "device openings: ");
2574                 }
2575                 fprintf(stdout, "%d\n", ccb->cgds.dev_openings +
2576                         ccb->cgds.dev_active);
2577         }
2578
2579 tagcontrol_bailout:
2580
2581         cam_freeccb(ccb);
2582         return(retval);
2583 }
2584
2585 static void
2586 cts_print(struct cam_device *device, struct ccb_trans_settings *cts)
2587 {
2588         char pathstr[1024];
2589
2590         cam_path_string(device, pathstr, sizeof(pathstr));
2591
2592         if (cts->transport == XPORT_SPI) {
2593                 struct ccb_trans_settings_spi *spi =
2594                     &cts->xport_specific.spi;
2595
2596                 if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) {
2597
2598                         fprintf(stdout, "%ssync parameter: %d\n", pathstr,
2599                                 spi->sync_period);
2600
2601                         if (spi->sync_offset != 0) {
2602                                 u_int freq;
2603
2604                                 freq = scsi_calc_syncsrate(spi->sync_period);
2605                                 fprintf(stdout, "%sfrequency: %d.%03dMHz\n",
2606                                         pathstr, freq / 1000, freq % 1000);
2607                         }
2608                 }
2609
2610                 if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) {
2611                         fprintf(stdout, "%soffset: %d\n", pathstr,
2612                             spi->sync_offset);
2613                 }
2614
2615                 if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) {
2616                         fprintf(stdout, "%sbus width: %d bits\n", pathstr,
2617                                 (0x01 << spi->bus_width) * 8);
2618                 }
2619
2620                 if (spi->valid & CTS_SPI_VALID_DISC) {
2621                         fprintf(stdout, "%sdisconnection is %s\n", pathstr,
2622                                 (spi->flags & CTS_SPI_FLAGS_DISC_ENB) ?
2623                                 "enabled" : "disabled");
2624                 }
2625         }
2626
2627         if (cts->protocol == PROTO_SCSI) {
2628                 struct ccb_trans_settings_scsi *scsi=
2629                     &cts->proto_specific.scsi;
2630
2631                 if (scsi->valid & CTS_SCSI_VALID_TQ) {
2632                         fprintf(stdout, "%stagged queueing is %s\n", pathstr,
2633                                 (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) ?
2634                                 "enabled" : "disabled");
2635                 }
2636         }
2637
2638 }
2639
2640 /*
2641  * Get a path inquiry CCB for the specified device.  
2642  */
2643 static int
2644 get_cpi(struct cam_device *device, struct ccb_pathinq *cpi)
2645 {
2646         union ccb *ccb;
2647         int retval = 0;
2648
2649         ccb = cam_getccb(device);
2650         if (ccb == NULL) {
2651                 warnx("get_cpi: couldn't allocate CCB");
2652                 return(1);
2653         }
2654         bzero(&(&ccb->ccb_h)[1],
2655               sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr));
2656         ccb->ccb_h.func_code = XPT_PATH_INQ;
2657         if (cam_send_ccb(device, ccb) < 0) {
2658                 warn("get_cpi: error sending Path Inquiry CCB");
2659                 if (arglist & CAM_ARG_VERBOSE)
2660                         cam_error_print(device, ccb, CAM_ESF_ALL,
2661                                         CAM_EPF_ALL, stderr);
2662                 retval = 1;
2663                 goto get_cpi_bailout;
2664         }
2665         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2666                 if (arglist & CAM_ARG_VERBOSE)
2667                         cam_error_print(device, ccb, CAM_ESF_ALL,
2668                                         CAM_EPF_ALL, stderr);
2669                 retval = 1;
2670                 goto get_cpi_bailout;
2671         }
2672         bcopy(&ccb->cpi, cpi, sizeof(struct ccb_pathinq));
2673
2674 get_cpi_bailout:
2675         cam_freeccb(ccb);
2676         return(retval);
2677 }
2678
2679 /*
2680  * Get a get device CCB for the specified device.  
2681  */
2682 static int
2683 get_cgd(struct cam_device *device, struct ccb_getdev *cgd)
2684 {
2685         union ccb *ccb;
2686         int retval = 0;
2687
2688         ccb = cam_getccb(device);
2689         if (ccb == NULL) {
2690                 warnx("get_cgd: couldn't allocate CCB");
2691                 return(1);
2692         }
2693         bzero(&(&ccb->ccb_h)[1],
2694               sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr));
2695         ccb->ccb_h.func_code = XPT_GDEV_TYPE;
2696         if (cam_send_ccb(device, ccb) < 0) {
2697                 warn("get_cgd: error sending Path Inquiry CCB");
2698                 if (arglist & CAM_ARG_VERBOSE)
2699                         cam_error_print(device, ccb, CAM_ESF_ALL,
2700                                         CAM_EPF_ALL, stderr);
2701                 retval = 1;
2702                 goto get_cgd_bailout;
2703         }
2704         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2705                 if (arglist & CAM_ARG_VERBOSE)
2706                         cam_error_print(device, ccb, CAM_ESF_ALL,
2707                                         CAM_EPF_ALL, stderr);
2708                 retval = 1;
2709                 goto get_cgd_bailout;
2710         }
2711         bcopy(&ccb->cgd, cgd, sizeof(struct ccb_getdev));
2712
2713 get_cgd_bailout:
2714         cam_freeccb(ccb);
2715         return(retval);
2716 }
2717
2718 static void
2719 cpi_print(struct ccb_pathinq *cpi)
2720 {
2721         char adapter_str[1024];
2722         int i;
2723
2724         snprintf(adapter_str, sizeof(adapter_str),
2725                  "%s%d:", cpi->dev_name, cpi->unit_number);
2726
2727         fprintf(stdout, "%s SIM/HBA version: %d\n", adapter_str,
2728                 cpi->version_num);
2729
2730         for (i = 1; i < 0xff; i = i << 1) {
2731                 const char *str;
2732
2733                 if ((i & cpi->hba_inquiry) == 0)
2734                         continue;
2735
2736                 fprintf(stdout, "%s supports ", adapter_str);
2737
2738                 switch(i) {
2739                 case PI_MDP_ABLE:
2740                         str = "MDP message";
2741                         break;
2742                 case PI_WIDE_32:
2743                         str = "32 bit wide SCSI";
2744                         break;
2745                 case PI_WIDE_16:
2746                         str = "16 bit wide SCSI";
2747                         break;
2748                 case PI_SDTR_ABLE:
2749                         str = "SDTR message";
2750                         break;
2751                 case PI_LINKED_CDB:
2752                         str = "linked CDBs";
2753                         break;
2754                 case PI_TAG_ABLE:
2755                         str = "tag queue messages";
2756                         break;
2757                 case PI_SOFT_RST:
2758                         str = "soft reset alternative";
2759                         break;
2760                 case PI_SATAPM:
2761                         str = "SATA Port Multiplier";
2762                         break;
2763                 default:
2764                         str = "unknown PI bit set";
2765                         break;
2766                 }
2767                 fprintf(stdout, "%s\n", str);
2768         }
2769
2770         for (i = 1; i < 0xff; i = i << 1) {
2771                 const char *str;
2772
2773                 if ((i & cpi->hba_misc) == 0)
2774                         continue;
2775
2776                 fprintf(stdout, "%s ", adapter_str);
2777
2778                 switch(i) {
2779                 case PIM_SCANHILO:
2780                         str = "bus scans from high ID to low ID";
2781                         break;
2782                 case PIM_NOREMOVE:
2783                         str = "removable devices not included in scan";
2784                         break;
2785                 case PIM_NOINITIATOR:
2786                         str = "initiator role not supported";
2787                         break;
2788                 case PIM_NOBUSRESET:
2789                         str = "user has disabled initial BUS RESET or"
2790                               " controller is in target/mixed mode";
2791                         break;
2792                 case PIM_NO_6_BYTE:
2793                         str = "do not send 6-byte commands";
2794                         break;
2795                 case PIM_SEQSCAN:
2796                         str = "scan bus sequentially";
2797                         break;
2798                 default:
2799                         str = "unknown PIM bit set";
2800                         break;
2801                 }
2802                 fprintf(stdout, "%s\n", str);
2803         }
2804
2805         for (i = 1; i < 0xff; i = i << 1) {
2806                 const char *str;
2807
2808                 if ((i & cpi->target_sprt) == 0)
2809                         continue;
2810
2811                 fprintf(stdout, "%s supports ", adapter_str);
2812                 switch(i) {
2813                 case PIT_PROCESSOR:
2814                         str = "target mode processor mode";
2815                         break;
2816                 case PIT_PHASE:
2817                         str = "target mode phase cog. mode";
2818                         break;
2819                 case PIT_DISCONNECT:
2820                         str = "disconnects in target mode";
2821                         break;
2822                 case PIT_TERM_IO:
2823                         str = "terminate I/O message in target mode";
2824                         break;
2825                 case PIT_GRP_6:
2826                         str = "group 6 commands in target mode";
2827                         break;
2828                 case PIT_GRP_7:
2829                         str = "group 7 commands in target mode";
2830                         break;
2831                 default:
2832                         str = "unknown PIT bit set";
2833                         break;
2834                 }
2835
2836                 fprintf(stdout, "%s\n", str);
2837         }
2838         fprintf(stdout, "%s HBA engine count: %d\n", adapter_str,
2839                 cpi->hba_eng_cnt);
2840         fprintf(stdout, "%s maximum target: %d\n", adapter_str,
2841                 cpi->max_target);
2842         fprintf(stdout, "%s maximum LUN: %d\n", adapter_str,
2843                 cpi->max_lun);
2844         fprintf(stdout, "%s highest path ID in subsystem: %d\n",
2845                 adapter_str, cpi->hpath_id);
2846         fprintf(stdout, "%s initiator ID: %d\n", adapter_str,
2847                 cpi->initiator_id);
2848         fprintf(stdout, "%s SIM vendor: %s\n", adapter_str, cpi->sim_vid);
2849         fprintf(stdout, "%s HBA vendor: %s\n", adapter_str, cpi->hba_vid);
2850         fprintf(stdout, "%s bus ID: %d\n", adapter_str, cpi->bus_id);
2851         fprintf(stdout, "%s base transfer speed: ", adapter_str);
2852         if (cpi->base_transfer_speed > 1000)
2853                 fprintf(stdout, "%d.%03dMB/sec\n",
2854                         cpi->base_transfer_speed / 1000,
2855                         cpi->base_transfer_speed % 1000);
2856         else
2857                 fprintf(stdout, "%dKB/sec\n",
2858                         (cpi->base_transfer_speed % 1000) * 1000);
2859 }
2860
2861 static int
2862 get_print_cts(struct cam_device *device, int user_settings, int quiet,
2863               struct ccb_trans_settings *cts)
2864 {
2865         int retval;
2866         union ccb *ccb;
2867
2868         retval = 0;
2869         ccb = cam_getccb(device);
2870
2871         if (ccb == NULL) {
2872                 warnx("get_print_cts: error allocating ccb");
2873                 return(1);
2874         }
2875
2876         bzero(&(&ccb->ccb_h)[1],
2877               sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr));
2878
2879         ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
2880
2881         if (user_settings == 0)
2882                 ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS;
2883         else
2884                 ccb->cts.type = CTS_TYPE_USER_SETTINGS;
2885
2886         if (cam_send_ccb(device, ccb) < 0) {
2887                 perror("error sending XPT_GET_TRAN_SETTINGS CCB");
2888                 if (arglist & CAM_ARG_VERBOSE)
2889                         cam_error_print(device, ccb, CAM_ESF_ALL,
2890                                         CAM_EPF_ALL, stderr);
2891                 retval = 1;
2892                 goto get_print_cts_bailout;
2893         }
2894
2895         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2896                 warnx("XPT_GET_TRANS_SETTINGS CCB failed");
2897                 if (arglist & CAM_ARG_VERBOSE)
2898                         cam_error_print(device, ccb, CAM_ESF_ALL,
2899                                         CAM_EPF_ALL, stderr);
2900                 retval = 1;
2901                 goto get_print_cts_bailout;
2902         }
2903
2904         if (quiet == 0)
2905                 cts_print(device, &ccb->cts);
2906
2907         if (cts != NULL)
2908                 bcopy(&ccb->cts, cts, sizeof(struct ccb_trans_settings));
2909
2910 get_print_cts_bailout:
2911
2912         cam_freeccb(ccb);
2913
2914         return(retval);
2915 }
2916
2917 static int
2918 ratecontrol(struct cam_device *device, int retry_count, int timeout,
2919             int argc, char **argv, char *combinedopt)
2920 {
2921         int c;
2922         union ccb *ccb;
2923         int user_settings = 0;
2924         int retval = 0;
2925         int disc_enable = -1, tag_enable = -1;
2926         int offset = -1;
2927         double syncrate = -1;
2928         int bus_width = -1;
2929         int quiet = 0;
2930         int change_settings = 0, send_tur = 0;
2931         struct ccb_pathinq cpi;
2932
2933         ccb = cam_getccb(device);
2934
2935         if (ccb == NULL) {
2936                 warnx("ratecontrol: error allocating ccb");
2937                 return(1);
2938         }
2939
2940         while ((c = getopt(argc, argv, combinedopt)) != -1) {
2941                 switch(c){
2942                 case 'a':
2943                         send_tur = 1;
2944                         break;
2945                 case 'c':
2946                         user_settings = 0;
2947                         break;
2948                 case 'D':
2949                         if (strncasecmp(optarg, "enable", 6) == 0)
2950                                 disc_enable = 1;
2951                         else if (strncasecmp(optarg, "disable", 7) == 0)
2952                                 disc_enable = 0;
2953                         else {
2954                                 warnx("-D argument \"%s\" is unknown", optarg);
2955                                 retval = 1;
2956                                 goto ratecontrol_bailout;
2957                         }
2958                         change_settings = 1;
2959                         break;
2960                 case 'O':
2961                         offset = strtol(optarg, NULL, 0);
2962                         if (offset < 0) {
2963                                 warnx("offset value %d is < 0", offset);
2964                                 retval = 1;
2965                                 goto ratecontrol_bailout;
2966                         }
2967                         change_settings = 1;
2968                         break;
2969                 case 'q':
2970                         quiet++;
2971                         break;
2972                 case 'R':
2973                         syncrate = atof(optarg);
2974
2975                         if (syncrate < 0) {
2976                                 warnx("sync rate %f is < 0", syncrate);
2977                                 retval = 1;
2978                                 goto ratecontrol_bailout;
2979                         }
2980                         change_settings = 1;
2981                         break;
2982                 case 'T':
2983                         if (strncasecmp(optarg, "enable", 6) == 0)
2984                                 tag_enable = 1;
2985                         else if (strncasecmp(optarg, "disable", 7) == 0)
2986                                 tag_enable = 0;
2987                         else {
2988                                 warnx("-T argument \"%s\" is unknown", optarg);
2989                                 retval = 1;
2990                                 goto ratecontrol_bailout;
2991                         }
2992                         change_settings = 1;
2993                         break;
2994                 case 'U':
2995                         user_settings = 1;
2996                         break;
2997                 case 'W':
2998                         bus_width = strtol(optarg, NULL, 0);
2999                         if (bus_width < 0) {
3000                                 warnx("bus width %d is < 0", bus_width);
3001                                 retval = 1;
3002                                 goto ratecontrol_bailout;
3003                         }
3004                         change_settings = 1;
3005                         break;
3006                 default:
3007                         break;
3008                 }
3009         }
3010
3011         bzero(&(&ccb->ccb_h)[1],
3012               sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr));
3013
3014         /*
3015          * Grab path inquiry information, so we can determine whether
3016          * or not the initiator is capable of the things that the user
3017          * requests.
3018          */
3019         ccb->ccb_h.func_code = XPT_PATH_INQ;
3020
3021         if (cam_send_ccb(device, ccb) < 0) {
3022                 perror("error sending XPT_PATH_INQ CCB");
3023                 if (arglist & CAM_ARG_VERBOSE) {
3024                         cam_error_print(device, ccb, CAM_ESF_ALL,
3025                                         CAM_EPF_ALL, stderr);
3026                 }
3027                 retval = 1;
3028                 goto ratecontrol_bailout;
3029         }
3030
3031         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3032                 warnx("XPT_PATH_INQ CCB failed");
3033                 if (arglist & CAM_ARG_VERBOSE) {
3034                         cam_error_print(device, ccb, CAM_ESF_ALL,
3035                                         CAM_EPF_ALL, stderr);
3036                 }
3037                 retval = 1;
3038                 goto ratecontrol_bailout;
3039         }
3040
3041         bcopy(&ccb->cpi, &cpi, sizeof(struct ccb_pathinq));
3042
3043         bzero(&(&ccb->ccb_h)[1],
3044               sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr));
3045
3046         if (quiet == 0)
3047                 fprintf(stdout, "Current Parameters:\n");
3048
3049         retval = get_print_cts(device, user_settings, quiet, &ccb->cts);
3050
3051         if (retval != 0)
3052                 goto ratecontrol_bailout;
3053
3054         if (arglist & CAM_ARG_VERBOSE)
3055                 cpi_print(&cpi);
3056
3057         if (change_settings) {
3058                 int didsettings = 0;
3059                 struct ccb_trans_settings_spi *spi = NULL;
3060                 struct ccb_trans_settings_scsi *scsi = NULL;
3061
3062                 if (ccb->cts.transport == XPORT_SPI) {
3063                         spi = &ccb->cts.xport_specific.spi;
3064                         spi->valid = 0;
3065                 }
3066                 if (ccb->cts.protocol == PROTO_SCSI) {
3067                         scsi = &ccb->cts.proto_specific.scsi;
3068                         scsi->valid = 0;
3069                 }
3070                 if (spi && disc_enable != -1) {
3071                         spi->valid |= CTS_SPI_VALID_DISC;
3072                         if (disc_enable == 0)
3073                                 spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
3074                         else
3075                                 spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
3076                 }
3077
3078                 if (scsi && tag_enable != -1) {
3079                         if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0) {
3080                                 warnx("HBA does not support tagged queueing, "
3081                                       "so you cannot modify tag settings");
3082                                 retval = 1;
3083                                 goto ratecontrol_bailout;
3084                         }
3085
3086                         scsi->valid |= CTS_SCSI_VALID_TQ;
3087
3088                         if (tag_enable == 0)
3089                                 scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
3090                         else
3091                                 scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
3092                         didsettings++;
3093                 }
3094
3095                 if (spi && offset != -1) {
3096                         if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
3097                                 warnx("HBA at %s%d is not cable of changing "
3098                                       "offset", cpi.dev_name,
3099                                       cpi.unit_number);
3100                                 retval = 1;
3101                                 goto ratecontrol_bailout;
3102                         }
3103                         spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
3104                         spi->sync_offset = offset;
3105                         didsettings++;
3106                 }
3107
3108                 if (spi && syncrate != -1) {
3109                         int prelim_sync_period;
3110                         u_int freq;
3111
3112                         if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
3113                                 warnx("HBA at %s%d is not cable of changing "
3114                                       "transfer rates", cpi.dev_name,
3115                                       cpi.unit_number);
3116                                 retval = 1;
3117                                 goto ratecontrol_bailout;
3118                         }
3119
3120                         spi->valid |= CTS_SPI_VALID_SYNC_RATE;
3121
3122                         /*
3123                          * The sync rate the user gives us is in MHz.
3124                          * We need to translate it into KHz for this
3125                          * calculation.
3126                          */
3127                         syncrate *= 1000;
3128
3129                         /*
3130                          * Next, we calculate a "preliminary" sync period
3131                          * in tenths of a nanosecond.
3132                          */
3133                         if (syncrate == 0)
3134                                 prelim_sync_period = 0;
3135                         else
3136                                 prelim_sync_period = 10000000 / syncrate;
3137
3138                         spi->sync_period =
3139                                 scsi_calc_syncparam(prelim_sync_period);
3140
3141                         freq = scsi_calc_syncsrate(spi->sync_period);
3142                         didsettings++;
3143                 }
3144
3145                 /*
3146                  * The bus_width argument goes like this:
3147                  * 0 == 8 bit
3148                  * 1 == 16 bit
3149                  * 2 == 32 bit
3150                  * Therefore, if you shift the number of bits given on the
3151                  * command line right by 4, you should get the correct
3152                  * number.
3153                  */
3154                 if (spi && bus_width != -1) {
3155
3156                         /*
3157                          * We might as well validate things here with a
3158                          * decipherable error message, rather than what
3159                          * will probably be an indecipherable error message
3160                          * by the time it gets back to us.
3161                          */
3162                         if ((bus_width == 16)
3163                          && ((cpi.hba_inquiry & PI_WIDE_16) == 0)) {
3164                                 warnx("HBA does not support 16 bit bus width");
3165                                 retval = 1;
3166                                 goto ratecontrol_bailout;
3167                         } else if ((bus_width == 32)
3168                                 && ((cpi.hba_inquiry & PI_WIDE_32) == 0)) {
3169                                 warnx("HBA does not support 32 bit bus width");
3170                                 retval = 1;
3171                                 goto ratecontrol_bailout;
3172                         } else if ((bus_width != 8)
3173                                 && (bus_width != 16)
3174                                 && (bus_width != 32)) {
3175                                 warnx("Invalid bus width %d", bus_width);
3176                                 retval = 1;
3177                                 goto ratecontrol_bailout;
3178                         }
3179
3180                         spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
3181                         spi->bus_width = bus_width >> 4;
3182                         didsettings++;
3183                 }
3184
3185                 if  (didsettings == 0) {
3186                         goto ratecontrol_bailout;
3187                 }
3188                 ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
3189
3190                 if (cam_send_ccb(device, ccb) < 0) {
3191                         perror("error sending XPT_SET_TRAN_SETTINGS CCB");
3192                         if (arglist & CAM_ARG_VERBOSE) {
3193                                 cam_error_print(device, ccb, CAM_ESF_ALL,
3194                                                 CAM_EPF_ALL, stderr);
3195                         }
3196                         retval = 1;
3197                         goto ratecontrol_bailout;
3198                 }
3199
3200                 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3201                         warnx("XPT_SET_TRANS_SETTINGS CCB failed");
3202                         if (arglist & CAM_ARG_VERBOSE) {
3203                                 cam_error_print(device, ccb, CAM_ESF_ALL,
3204                                                 CAM_EPF_ALL, stderr);
3205                         }
3206                         retval = 1;
3207                         goto ratecontrol_bailout;
3208                 }
3209         }
3210
3211         if (send_tur) {
3212                 retval = testunitready(device, retry_count, timeout,
3213                                        (arglist & CAM_ARG_VERBOSE) ? 0 : 1);
3214
3215                 /*
3216                  * If the TUR didn't succeed, just bail.
3217                  */
3218                 if (retval != 0) {
3219                         if (quiet == 0)
3220                                 fprintf(stderr, "Test Unit Ready failed\n");
3221                         goto ratecontrol_bailout;
3222                 }
3223
3224                 /*
3225                  * If the user wants things quiet, there's no sense in
3226                  * getting the transfer settings, if we're not going
3227                  * to print them.
3228                  */
3229                 if (quiet != 0)
3230                         goto ratecontrol_bailout;
3231
3232                 fprintf(stdout, "New Parameters:\n");
3233                 retval = get_print_cts(device, user_settings, 0, NULL);
3234         }
3235
3236 ratecontrol_bailout:
3237
3238         cam_freeccb(ccb);
3239         return(retval);
3240 }
3241
3242 static int
3243 scsiformat(struct cam_device *device, int argc, char **argv,
3244            char *combinedopt, int retry_count, int timeout)
3245 {
3246         union ccb *ccb;
3247         int c;
3248         int ycount = 0, quiet = 0;
3249         int error = 0, response = 0, retval = 0;
3250         int use_timeout = 10800 * 1000;
3251         int immediate = 1;
3252         struct format_defect_list_header fh;
3253         u_int8_t *data_ptr = NULL;
3254         u_int32_t dxfer_len = 0;
3255         u_int8_t byte2 = 0;
3256         int num_warnings = 0;
3257         int reportonly = 0;
3258
3259         ccb = cam_getccb(device);
3260
3261         if (ccb == NULL) {
3262                 warnx("scsiformat: error allocating ccb");
3263                 return(1);
3264         }
3265
3266         bzero(&(&ccb->ccb_h)[1],
3267               sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
3268
3269         while ((c = getopt(argc, argv, combinedopt)) != -1) {
3270                 switch(c) {
3271                 case 'q':
3272                         quiet++;
3273                         break;
3274                 case 'r':
3275                         reportonly = 1;
3276                         break;
3277                 case 'w':
3278                         immediate = 0;
3279                         break;
3280                 case 'y':
3281                         ycount++;
3282                         break;
3283                 }
3284         }
3285
3286         if (reportonly)
3287                 goto doreport;
3288
3289         if (quiet == 0) {
3290                 fprintf(stdout, "You are about to REMOVE ALL DATA from the "
3291                         "following device:\n");
3292
3293                 error = scsidoinquiry(device, argc, argv, combinedopt,
3294                                       retry_count, timeout);
3295
3296                 if (error != 0) {
3297                         warnx("scsiformat: error sending inquiry");
3298                         goto scsiformat_bailout;
3299                 }
3300         }
3301
3302         if (ycount == 0) {
3303
3304                 do {
3305                         char str[1024];
3306
3307                         fprintf(stdout, "Are you SURE you want to do "
3308                                 "this? (yes/no) ");
3309
3310                         if (fgets(str, sizeof(str), stdin) != NULL) {
3311
3312                                 if (strncasecmp(str, "yes", 3) == 0)
3313                                         response = 1;
3314                                 else if (strncasecmp(str, "no", 2) == 0)
3315                                         response = -1;
3316                                 else {
3317                                         fprintf(stdout, "Please answer"
3318                                                 " \"yes\" or \"no\"\n");
3319                                 }
3320                         }
3321                 } while (response == 0);
3322
3323                 if (response == -1) {
3324                         error = 1;
3325                         goto scsiformat_bailout;
3326                 }
3327         }
3328
3329         if (timeout != 0)
3330                 use_timeout = timeout;
3331
3332         if (quiet == 0) {
3333                 fprintf(stdout, "Current format timeout is %d seconds\n",
3334                         use_timeout / 1000);
3335         }
3336
3337         /*
3338          * If the user hasn't disabled questions and didn't specify a
3339          * timeout on the command line, ask them if they want the current
3340          * timeout.
3341          */
3342         if ((ycount == 0)
3343          && (timeout == 0)) {
3344                 char str[1024];
3345                 int new_timeout = 0;
3346
3347                 fprintf(stdout, "Enter new timeout in seconds or press\n"
3348                         "return to keep the current timeout [%d] ",
3349                         use_timeout / 1000);
3350
3351                 if (fgets(str, sizeof(str), stdin) != NULL) {
3352                         if (str[0] != '\0')
3353                                 new_timeout = atoi(str);
3354                 }
3355
3356                 if (new_timeout != 0) {
3357                         use_timeout = new_timeout * 1000;
3358                         fprintf(stdout, "Using new timeout value %d\n",
3359                                 use_timeout / 1000);
3360                 }
3361         }
3362
3363         /*
3364          * Keep this outside the if block below to silence any unused
3365          * variable warnings.
3366          */
3367         bzero(&fh, sizeof(fh));
3368
3369         /*
3370          * If we're in immediate mode, we've got to include the format
3371          * header
3372          */
3373         if (immediate != 0) {
3374                 fh.byte2 = FU_DLH_IMMED;
3375                 data_ptr = (u_int8_t *)&fh;
3376                 dxfer_len = sizeof(fh);
3377                 byte2 = FU_FMT_DATA;
3378         } else if (quiet == 0) {
3379                 fprintf(stdout, "Formatting...");
3380                 fflush(stdout);
3381         }
3382
3383         scsi_format_unit(&ccb->csio,
3384                          /* retries */ retry_count,
3385                          /* cbfcnp */ NULL,
3386                          /* tag_action */ MSG_SIMPLE_Q_TAG,
3387                          /* byte2 */ byte2,
3388                          /* ileave */ 0,
3389                          /* data_ptr */ data_ptr,
3390                          /* dxfer_len */ dxfer_len,
3391                          /* sense_len */ SSD_FULL_SIZE,
3392                          /* timeout */ use_timeout);
3393
3394         /* Disable freezing the device queue */
3395         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
3396
3397         if (arglist & CAM_ARG_ERR_RECOVER)
3398                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
3399
3400         if (((retval = cam_send_ccb(device, ccb)) < 0)
3401          || ((immediate == 0)
3402            && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP))) {
3403                 const char errstr[] = "error sending format command";
3404
3405                 if (retval < 0)
3406                         warn(errstr);
3407                 else
3408                         warnx(errstr);
3409
3410                 if (arglist & CAM_ARG_VERBOSE) {
3411                         cam_error_print(device, ccb, CAM_ESF_ALL,
3412                                         CAM_EPF_ALL, stderr);
3413                 }
3414                 error = 1;
3415                 goto scsiformat_bailout;
3416         }
3417
3418         /*
3419          * If we ran in non-immediate mode, we already checked for errors
3420          * above and printed out any necessary information.  If we're in
3421          * immediate mode, we need to loop through and get status
3422          * information periodically.
3423          */
3424         if (immediate == 0) {
3425                 if (quiet == 0) {
3426                         fprintf(stdout, "Format Complete\n");
3427                 }
3428                 goto scsiformat_bailout;
3429         }
3430
3431 doreport:
3432         do {
3433                 cam_status status;
3434
3435                 bzero(&(&ccb->ccb_h)[1],
3436                       sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
3437
3438                 /*
3439                  * There's really no need to do error recovery or
3440                  * retries here, since we're just going to sit in a
3441                  * loop and wait for the device to finish formatting.
3442                  */
3443                 scsi_test_unit_ready(&ccb->csio,
3444                                      /* retries */ 0,
3445                                      /* cbfcnp */ NULL,
3446                                      /* tag_action */ MSG_SIMPLE_Q_TAG,
3447                                      /* sense_len */ SSD_FULL_SIZE,
3448                                      /* timeout */ 5000);
3449
3450                 /* Disable freezing the device queue */
3451                 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
3452
3453                 retval = cam_send_ccb(device, ccb);
3454
3455                 /*
3456                  * If we get an error from the ioctl, bail out.  SCSI
3457                  * errors are expected.
3458                  */
3459                 if (retval < 0) {
3460                         warn("error sending CAMIOCOMMAND ioctl");
3461                         if (arglist & CAM_ARG_VERBOSE) {
3462                                 cam_error_print(device, ccb, CAM_ESF_ALL,
3463                                                 CAM_EPF_ALL, stderr);
3464                         }
3465                         error = 1;
3466                         goto scsiformat_bailout;
3467                 }
3468
3469                 status = ccb->ccb_h.status & CAM_STATUS_MASK;
3470
3471                 if ((status != CAM_REQ_CMP)
3472                  && (status == CAM_SCSI_STATUS_ERROR)
3473                  && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) {
3474                         struct scsi_sense_data *sense;
3475                         int error_code, sense_key, asc, ascq;
3476
3477                         sense = &ccb->csio.sense_data;
3478                         scsi_extract_sense(sense, &error_code, &sense_key,
3479                                            &asc, &ascq);
3480
3481                         /*
3482                          * According to the SCSI-2 and SCSI-3 specs, a
3483                          * drive that is in the middle of a format should
3484                          * return NOT READY with an ASC of "logical unit
3485                          * not ready, format in progress".  The sense key
3486                          * specific bytes will then be a progress indicator.
3487                          */
3488                         if ((sense_key == SSD_KEY_NOT_READY)
3489                          && (asc == 0x04) && (ascq == 0x04)) {
3490                                 if ((sense->extra_len >= 10)
3491                                  && ((sense->sense_key_spec[0] &
3492                                       SSD_SCS_VALID) != 0)
3493                                  && (quiet == 0)) {
3494                                         int val;
3495                                         u_int64_t percentage;
3496
3497                                         val = scsi_2btoul(
3498                                                 &sense->sense_key_spec[1]);
3499                                         percentage = 10000 * val;
3500
3501                                         fprintf(stdout,
3502                                                 "\rFormatting:  %ju.%02u %% "
3503                                                 "(%d/%d) done",
3504                                                 (uintmax_t)(percentage / 
3505                                                 (0x10000 * 100)),
3506                                                 (unsigned)((percentage / 
3507                                                 0x10000) % 100),
3508                                                 val, 0x10000);
3509                                         fflush(stdout);
3510                                 } else if ((quiet == 0)
3511                                         && (++num_warnings <= 1)) {
3512                                         warnx("Unexpected SCSI Sense Key "
3513                                               "Specific value returned "
3514                                               "during format:");
3515                                         scsi_sense_print(device, &ccb->csio,
3516                                                          stderr);
3517                                         warnx("Unable to print status "
3518                                               "information, but format will "
3519                                               "proceed.");
3520                                         warnx("will exit when format is "
3521                                               "complete");
3522                                 }
3523                                 sleep(1);
3524                         } else {
3525                                 warnx("Unexpected SCSI error during format");
3526                                 cam_error_print(device, ccb, CAM_ESF_ALL,
3527                                                 CAM_EPF_ALL, stderr);
3528                                 error = 1;
3529                                 goto scsiformat_bailout;
3530                         }
3531
3532                 } else if (status != CAM_REQ_CMP) {
3533                         warnx("Unexpected CAM status %#x", status);
3534                         if (arglist & CAM_ARG_VERBOSE)
3535                                 cam_error_print(device, ccb, CAM_ESF_ALL,
3536                                                 CAM_EPF_ALL, stderr);
3537                         error = 1;
3538                         goto scsiformat_bailout;
3539                 }
3540
3541         } while((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP);
3542
3543         if (quiet == 0)
3544                 fprintf(stdout, "\nFormat Complete\n");
3545
3546 scsiformat_bailout:
3547
3548         cam_freeccb(ccb);
3549
3550         return(error);
3551 }
3552
3553 static int
3554 scsireportluns(struct cam_device *device, int argc, char **argv,
3555                char *combinedopt, int retry_count, int timeout)
3556 {
3557         union ccb *ccb;
3558         int c, countonly, lunsonly;
3559         struct scsi_report_luns_data *lundata;
3560         int alloc_len;
3561         uint8_t report_type;
3562         uint32_t list_len, i, j;
3563         int retval;
3564
3565         retval = 0;
3566         lundata = NULL;
3567         report_type = RPL_REPORT_DEFAULT;
3568         ccb = cam_getccb(device);
3569
3570         if (ccb == NULL) {
3571                 warnx("%s: error allocating ccb", __func__);
3572                 return (1);
3573         }
3574
3575         bzero(&(&ccb->ccb_h)[1],
3576               sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
3577
3578         countonly = 0;
3579         lunsonly = 0;
3580
3581         while ((c = getopt(argc, argv, combinedopt)) != -1) {
3582                 switch (c) {
3583                 case 'c':
3584                         countonly++;
3585                         break;
3586                 case 'l':
3587                         lunsonly++;
3588                         break;
3589                 case 'r':
3590                         if (strcasecmp(optarg, "default") == 0)
3591                                 report_type = RPL_REPORT_DEFAULT;
3592                         else if (strcasecmp(optarg, "wellknown") == 0)
3593                                 report_type = RPL_REPORT_WELLKNOWN;
3594                         else if (strcasecmp(optarg, "all") == 0)
3595                                 report_type = RPL_REPORT_ALL;
3596                         else {
3597                                 warnx("%s: invalid report type \"%s\"",
3598                                       __func__, optarg);
3599                                 retval = 1;
3600                                 goto bailout;
3601                         }
3602                         break;
3603                 default:
3604                         break;
3605                 }
3606         }
3607
3608         if ((countonly != 0)
3609          && (lunsonly != 0)) {
3610                 warnx("%s: you can only specify one of -c or -l", __func__);
3611                 retval = 1;
3612                 goto bailout;
3613         }
3614         /*
3615          * According to SPC-4, the allocation length must be at least 16
3616          * bytes -- enough for the header and one LUN.
3617          */
3618         alloc_len = sizeof(*lundata) + 8;
3619
3620 retry:
3621
3622         lundata = malloc(alloc_len);
3623
3624         if (lundata == NULL) {
3625                 warn("%s: error mallocing %d bytes", __func__, alloc_len);
3626                 retval = 1;
3627                 goto bailout;
3628         }
3629
3630         scsi_report_luns(&ccb->csio,
3631                          /*retries*/ retry_count,
3632                          /*cbfcnp*/ NULL,
3633                          /*tag_action*/ MSG_SIMPLE_Q_TAG,
3634                          /*select_report*/ report_type,
3635                          /*rpl_buf*/ lundata,
3636                          /*alloc_len*/ alloc_len,
3637                          /*sense_len*/ SSD_FULL_SIZE,
3638                          /*timeout*/ timeout ? timeout : 5000);
3639
3640         /* Disable freezing the device queue */
3641         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
3642
3643         if (arglist & CAM_ARG_ERR_RECOVER)
3644                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
3645
3646         if (cam_send_ccb(device, ccb) < 0) {
3647                 warn("error sending REPORT LUNS command");
3648
3649                 if (arglist & CAM_ARG_VERBOSE)
3650                         cam_error_print(device, ccb, CAM_ESF_ALL,
3651                                         CAM_EPF_ALL, stderr);
3652
3653                 retval = 1;
3654                 goto bailout;
3655         }
3656
3657         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3658                 cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
3659                 retval = 1;
3660                 goto bailout;
3661         }
3662
3663
3664         list_len = scsi_4btoul(lundata->length);
3665
3666         /*
3667          * If we need to list the LUNs, and our allocation
3668          * length was too short, reallocate and retry.
3669          */
3670         if ((countonly == 0)
3671          && (list_len > (alloc_len - sizeof(*lundata)))) {
3672                 alloc_len = list_len + sizeof(*lundata);
3673                 free(lundata);
3674                 goto retry;
3675         }
3676
3677         if (lunsonly == 0)
3678                 fprintf(stdout, "%u LUN%s found\n", list_len / 8,
3679                         ((list_len / 8) > 1) ? "s" : "");
3680
3681         if (countonly != 0)
3682                 goto bailout;
3683
3684         for (i = 0; i < (list_len / 8); i++) {
3685                 int no_more;
3686
3687                 no_more = 0;
3688                 for (j = 0; j < sizeof(lundata->luns[i].lundata); j += 2) {
3689                         if (j != 0)
3690                                 fprintf(stdout, ",");
3691                         switch (lundata->luns[i].lundata[j] &
3692                                 RPL_LUNDATA_ATYP_MASK) {
3693                         case RPL_LUNDATA_ATYP_PERIPH:
3694                                 if ((lundata->luns[i].lundata[j] &
3695                                     RPL_LUNDATA_PERIPH_BUS_MASK) != 0)
3696                                         fprintf(stdout, "%d:", 
3697                                                 lundata->luns[i].lundata[j] &
3698                                                 RPL_LUNDATA_PERIPH_BUS_MASK);
3699                                 else if ((j == 0)
3700                                       && ((lundata->luns[i].lundata[j+2] &
3701                                           RPL_LUNDATA_PERIPH_BUS_MASK) == 0))
3702                                         no_more = 1;
3703
3704                                 fprintf(stdout, "%d",
3705                                         lundata->luns[i].lundata[j+1]);
3706                                 break;
3707                         case RPL_LUNDATA_ATYP_FLAT: {
3708                                 uint8_t tmplun[2];
3709                                 tmplun[0] = lundata->luns[i].lundata[j] &
3710                                         RPL_LUNDATA_FLAT_LUN_MASK;
3711                                 tmplun[1] = lundata->luns[i].lundata[j+1];
3712
3713                                 fprintf(stdout, "%d", scsi_2btoul(tmplun));
3714                                 no_more = 1;
3715                                 break;
3716                         }
3717                         case RPL_LUNDATA_ATYP_LUN:
3718                                 fprintf(stdout, "%d:%d:%d",
3719                                         (lundata->luns[i].lundata[j+1] &
3720                                         RPL_LUNDATA_LUN_BUS_MASK) >> 5,
3721                                         lundata->luns[i].lundata[j] &
3722                                         RPL_LUNDATA_LUN_TARG_MASK,
3723                                         lundata->luns[i].lundata[j+1] &
3724                                         RPL_LUNDATA_LUN_LUN_MASK);
3725                                 break;
3726                         case RPL_LUNDATA_ATYP_EXTLUN: {
3727                                 int field_len, field_len_code, eam_code;
3728
3729                                 eam_code = lundata->luns[i].lundata[j] &
3730                                         RPL_LUNDATA_EXT_EAM_MASK;
3731                                 field_len_code = (lundata->luns[i].lundata[j] &
3732                                         RPL_LUNDATA_EXT_LEN_MASK) >> 4;
3733                                 field_len = field_len_code * 2;
3734                 
3735                                 if ((eam_code == RPL_LUNDATA_EXT_EAM_WK)
3736                                  && (field_len_code == 0x00)) {
3737                                         fprintf(stdout, "%d",
3738                                                 lundata->luns[i].lundata[j+1]);
3739                                 } else if ((eam_code ==
3740                                             RPL_LUNDATA_EXT_EAM_NOT_SPEC)
3741                                         && (field_len_code == 0x03)) {
3742                                         uint8_t tmp_lun[8];
3743
3744                                         /*
3745                                          * This format takes up all 8 bytes.
3746                                          * If we aren't starting at offset 0,
3747                                          * that's a bug.
3748                                          */
3749                                         if (j != 0) {
3750                                                 fprintf(stdout, "Invalid "
3751                                                         "offset %d for "
3752                                                         "Extended LUN not "
3753                                                         "specified format", j);
3754                                                 no_more = 1;
3755                                                 break;
3756                                         }
3757                                         bzero(tmp_lun, sizeof(tmp_lun));
3758                                         bcopy(&lundata->luns[i].lundata[j+1],
3759                                               &tmp_lun[1], sizeof(tmp_lun) - 1);
3760                                         fprintf(stdout, "%#jx",
3761                                                (intmax_t)scsi_8btou64(tmp_lun));
3762                                         no_more = 1;
3763                                 } else {
3764                                         fprintf(stderr, "Unknown Extended LUN"
3765                                                 "Address method %#x, length "
3766                                                 "code %#x", eam_code,
3767                                                 field_len_code);
3768                                         no_more = 1;
3769                                 }
3770                                 break;
3771                         }
3772                         default:
3773                                 fprintf(stderr, "Unknown LUN address method "
3774                                         "%#x\n", lundata->luns[i].lundata[0] &
3775                                         RPL_LUNDATA_ATYP_MASK);
3776                                 break;
3777                         }
3778                         /*
3779                          * For the flat addressing method, there are no
3780                          * other levels after it.
3781                          */
3782                         if (no_more != 0)
3783                                 break;
3784                 }
3785                 fprintf(stdout, "\n");
3786         }
3787
3788 bailout:
3789
3790         cam_freeccb(ccb);
3791
3792         free(lundata);
3793
3794         return (retval);
3795 }
3796
3797 static int
3798 scsireadcapacity(struct cam_device *device, int argc, char **argv,
3799                  char *combinedopt, int retry_count, int timeout)
3800 {
3801         union ccb *ccb;
3802         int blocksizeonly, humanize, numblocks, quiet, sizeonly, baseten;
3803         struct scsi_read_capacity_data rcap;
3804         struct scsi_read_capacity_data_long rcaplong;
3805         uint64_t maxsector;
3806         uint32_t block_len;
3807         int retval;
3808         int c;
3809
3810         blocksizeonly = 0;
3811         humanize = 0;
3812         numblocks = 0;
3813         quiet = 0;
3814         sizeonly = 0;
3815         baseten = 0;
3816         retval = 0;
3817
3818         ccb = cam_getccb(device);
3819
3820         if (ccb == NULL) {
3821                 warnx("%s: error allocating ccb", __func__);
3822                 return (1);
3823         }
3824
3825         bzero(&(&ccb->ccb_h)[1],
3826               sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
3827
3828         while ((c = getopt(argc, argv, combinedopt)) != -1) {
3829                 switch (c) {
3830                 case 'b':
3831                         blocksizeonly++;
3832                         break;
3833                 case 'h':
3834                         humanize++;
3835                         baseten = 0;
3836                         break;
3837                 case 'H':
3838                         humanize++;
3839                         baseten++;
3840                         break;
3841                 case 'N':
3842                         numblocks++;
3843                         break;
3844                 case 'q':
3845                         quiet++;
3846                         break;
3847                 case 's':
3848                         sizeonly++;
3849                         break;
3850                 default:
3851                         break;
3852                 }
3853         }
3854
3855         if ((blocksizeonly != 0)
3856          && (numblocks != 0)) {
3857                 warnx("%s: you can only specify one of -b or -N", __func__);
3858                 retval = 1;
3859                 goto bailout;
3860         }
3861
3862         if ((blocksizeonly != 0)
3863          && (sizeonly != 0)) {
3864                 warnx("%s: you can only specify one of -b or -s", __func__);
3865                 retval = 1;
3866                 goto bailout;
3867         }
3868
3869         if ((humanize != 0)
3870          && (quiet != 0)) {
3871                 warnx("%s: you can only specify one of -h/-H or -q", __func__);
3872                 retval = 1;
3873                 goto bailout;
3874         }
3875
3876         if ((humanize != 0)
3877          && (blocksizeonly != 0)) {
3878                 warnx("%s: you can only specify one of -h/-H or -b", __func__);
3879                 retval = 1;
3880                 goto bailout;
3881         }
3882
3883         scsi_read_capacity(&ccb->csio,
3884                            /*retries*/ retry_count,
3885                            /*cbfcnp*/ NULL,
3886                            /*tag_action*/ MSG_SIMPLE_Q_TAG,
3887                            &rcap,
3888                            SSD_FULL_SIZE,
3889                            /*timeout*/ timeout ? timeout : 5000);
3890
3891         /* Disable freezing the device queue */
3892         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
3893
3894         if (arglist & CAM_ARG_ERR_RECOVER)
3895                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
3896
3897         if (cam_send_ccb(device, ccb) < 0) {
3898                 warn("error sending READ CAPACITY command");
3899
3900                 if (arglist & CAM_ARG_VERBOSE)
3901                         cam_error_print(device, ccb, CAM_ESF_ALL,
3902                                         CAM_EPF_ALL, stderr);
3903
3904                 retval = 1;
3905                 goto bailout;
3906         }
3907
3908         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3909                 cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
3910                 retval = 1;
3911                 goto bailout;
3912         }
3913
3914         maxsector = scsi_4btoul(rcap.addr);
3915         block_len = scsi_4btoul(rcap.length);
3916
3917         /*
3918          * A last block of 2^32-1 means that the true capacity is over 2TB,
3919          * and we need to issue the long READ CAPACITY to get the real
3920          * capacity.  Otherwise, we're all set.
3921          */
3922         if (maxsector != 0xffffffff)
3923                 goto do_print;
3924
3925         scsi_read_capacity_16(&ccb->csio,
3926                               /*retries*/ retry_count,
3927                               /*cbfcnp*/ NULL,
3928                               /*tag_action*/ MSG_SIMPLE_Q_TAG,
3929                               /*lba*/ 0,
3930                               /*reladdr*/ 0,
3931                               /*pmi*/ 0,
3932                               &rcaplong,
3933                               /*sense_len*/ SSD_FULL_SIZE,
3934                               /*timeout*/ timeout ? timeout : 5000);
3935
3936         /* Disable freezing the device queue */
3937         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
3938
3939         if (arglist & CAM_ARG_ERR_RECOVER)
3940                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
3941
3942         if (cam_send_ccb(device, ccb) < 0) {
3943                 warn("error sending READ CAPACITY (16) command");
3944
3945                 if (arglist & CAM_ARG_VERBOSE)
3946                         cam_error_print(device, ccb, CAM_ESF_ALL,
3947                                         CAM_EPF_ALL, stderr);
3948
3949                 retval = 1;
3950                 goto bailout;
3951         }
3952
3953         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3954                 cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
3955                 retval = 1;
3956                 goto bailout;
3957         }
3958
3959         maxsector = scsi_8btou64(rcaplong.addr);
3960         block_len = scsi_4btoul(rcaplong.length);
3961
3962 do_print:
3963         if (blocksizeonly == 0) {
3964                 /*
3965                  * Humanize implies !quiet, and also implies numblocks.
3966                  */
3967                 if (humanize != 0) {
3968                         char tmpstr[6];
3969                         int64_t tmpbytes;
3970                         int ret;
3971
3972                         tmpbytes = (maxsector + 1) * block_len;
3973                         ret = humanize_number(tmpstr, sizeof(tmpstr),
3974                                               tmpbytes, "", HN_AUTOSCALE,
3975                                               HN_B | HN_DECIMAL |
3976                                               ((baseten != 0) ?
3977                                               HN_DIVISOR_1000 : 0));
3978                         if (ret == -1) {
3979                                 warnx("%s: humanize_number failed!", __func__);
3980                                 retval = 1;
3981                                 goto bailout;
3982                         }
3983                         fprintf(stdout, "Device Size: %s%s", tmpstr,
3984                                 (sizeonly == 0) ?  ", " : "\n");
3985                 } else if (numblocks != 0) {
3986                         fprintf(stdout, "%s%ju%s", (quiet == 0) ?
3987                                 "Blocks: " : "", (uintmax_t)maxsector + 1,
3988                                 (sizeonly == 0) ? ", " : "\n");
3989                 } else {
3990                         fprintf(stdout, "%s%ju%s", (quiet == 0) ?
3991                                 "Last Block: " : "", (uintmax_t)maxsector,
3992                                 (sizeonly == 0) ? ", " : "\n");
3993                 }
3994         }
3995         if (sizeonly == 0)
3996                 fprintf(stdout, "%s%u%s\n", (quiet == 0) ?
3997                         "Block Length: " : "", block_len, (quiet == 0) ?
3998                         " bytes" : "");
3999 bailout:
4000         cam_freeccb(ccb);
4001
4002         return (retval);
4003 }
4004
4005 #endif /* MINIMALISTIC */
4006
4007 void 
4008 usage(int verbose)
4009 {
4010         fprintf(verbose ? stdout : stderr,
4011 "usage:  camcontrol <command>  [device id][generic args][command args]\n"
4012 "        camcontrol devlist    [-v]\n"
4013 #ifndef MINIMALISTIC
4014 "        camcontrol periphlist [dev_id][-n dev_name] [-u unit]\n"
4015 "        camcontrol tur        [dev_id][generic args]\n"
4016 "        camcontrol inquiry    [dev_id][generic args] [-D] [-S] [-R]\n"
4017 "        camcontrol identify   [dev_id][generic args]\n"
4018 "        camcontrol reportluns [dev_id][generic args] [-c] [-l] [-r report]\n"
4019 "        camcontrol readcap    [dev_id][generic args] [-b] [-h] [-H] [-N]\n"
4020 "                              [-q] [-s]\n"
4021 "        camcontrol start      [dev_id][generic args]\n"
4022 "        camcontrol stop       [dev_id][generic args]\n"
4023 "        camcontrol load       [dev_id][generic args]\n"
4024 "        camcontrol eject      [dev_id][generic args]\n"
4025 #endif /* MINIMALISTIC */
4026 "        camcontrol rescan     <all | bus[:target:lun]>\n"
4027 "        camcontrol reset      <all | bus[:target:lun]>\n"
4028 #ifndef MINIMALISTIC
4029 "        camcontrol defects    [dev_id][generic args] <-f format> [-P][-G]\n"
4030 "        camcontrol modepage   [dev_id][generic args] <-m page | -l>\n"
4031 "                              [-P pagectl][-e | -b][-d]\n"
4032 "        camcontrol cmd        [dev_id][generic args] <-c cmd [args]>\n"
4033 "                              [-i len fmt|-o len fmt [args]]\n"
4034 "        camcontrol debug      [-I][-P][-T][-S][-X][-c]\n"
4035 "                              <all|bus[:target[:lun]]|off>\n"
4036 "        camcontrol tags       [dev_id][generic args] [-N tags] [-q] [-v]\n"
4037 "        camcontrol negotiate  [dev_id][generic args] [-a][-c]\n"
4038 "                              [-D <enable|disable>][-O offset][-q]\n"
4039 "                              [-R syncrate][-v][-T <enable|disable>]\n"
4040 "                              [-U][-W bus_width]\n"
4041 "        camcontrol format     [dev_id][generic args][-q][-r][-w][-y]\n"
4042 #endif /* MINIMALISTIC */
4043 "        camcontrol help\n");
4044         if (!verbose)
4045                 return;
4046 #ifndef MINIMALISTIC
4047         fprintf(stdout,
4048 "Specify one of the following options:\n"
4049 "devlist     list all CAM devices\n"
4050 "periphlist  list all CAM peripheral drivers attached to a device\n"
4051 "tur         send a test unit ready to the named device\n"
4052 "inquiry     send a SCSI inquiry command to the named device\n"
4053 "identify    send a ATA identify command to the named device\n"
4054 "reportluns  send a SCSI report luns command to the device\n"
4055 "readcap     send a SCSI read capacity command to the device\n"
4056 "start       send a Start Unit command to the device\n"
4057 "stop        send a Stop Unit command to the device\n"
4058 "load        send a Start Unit command to the device with the load bit set\n"
4059 "eject       send a Stop Unit command to the device with the eject bit set\n"
4060 "rescan      rescan all busses, the given bus, or bus:target:lun\n"
4061 "reset       reset all busses, the given bus, or bus:target:lun\n"
4062 "defects     read the defect list of the specified device\n"
4063 "modepage    display or edit (-e) the given mode page\n"
4064 "cmd         send the given scsi command, may need -i or -o as well\n"
4065 "debug       turn debugging on/off for a bus, target, or lun, or all devices\n"
4066 "tags        report or set the number of transaction slots for a device\n"
4067 "negotiate   report or set device negotiation parameters\n"
4068 "format      send the SCSI FORMAT UNIT command to the named device\n"
4069 "help        this message\n"
4070 "Device Identifiers:\n"
4071 "bus:target        specify the bus and target, lun defaults to 0\n"
4072 "bus:target:lun    specify the bus, target and lun\n"
4073 "deviceUNIT        specify the device name, like \"da4\" or \"cd2\"\n"
4074 "Generic arguments:\n"
4075 "-v                be verbose, print out sense information\n"
4076 "-t timeout        command timeout in seconds, overrides default timeout\n"
4077 "-n dev_name       specify device name, e.g. \"da\", \"cd\"\n"
4078 "-u unit           specify unit number, e.g. \"0\", \"5\"\n"
4079 "-E                have the kernel attempt to perform SCSI error recovery\n"
4080 "-C count          specify the SCSI command retry count (needs -E to work)\n"
4081 "modepage arguments:\n"
4082 "-l                list all available mode pages\n"
4083 "-m page           specify the mode page to view or edit\n"
4084 "-e                edit the specified mode page\n"
4085 "-b                force view to binary mode\n"
4086 "-d                disable block descriptors for mode sense\n"
4087 "-P pgctl          page control field 0-3\n"
4088 "defects arguments:\n"
4089 "-f format         specify defect list format (block, bfi or phys)\n"
4090 "-G                get the grown defect list\n"
4091 "-P                get the permanant defect list\n"
4092 "inquiry arguments:\n"
4093 "-D                get the standard inquiry data\n"
4094 "-S                get the serial number\n"
4095 "-R                get the transfer rate, etc.\n"
4096 "reportluns arguments:\n"
4097 "-c                only report a count of available LUNs\n"
4098 "-l                only print out luns, and not a count\n"
4099 "-r <reporttype>   specify \"default\", \"wellknown\" or \"all\"\n"
4100 "readcap arguments\n"
4101 "-b                only report the blocksize\n"
4102 "-h                human readable device size, base 2\n"
4103 "-H                human readable device size, base 10\n"
4104 "-N                print the number of blocks instead of last block\n"
4105 "-q                quiet, print numbers only\n"
4106 "-s                only report the last block/device size\n"
4107 "cmd arguments:\n"
4108 "-c cdb [args]     specify the SCSI CDB\n"
4109 "-i len fmt        specify input data and input data format\n"
4110 "-o len fmt [args] specify output data and output data fmt\n"
4111 "debug arguments:\n"
4112 "-I                CAM_DEBUG_INFO -- scsi commands, errors, data\n"
4113 "-T                CAM_DEBUG_TRACE -- routine flow tracking\n"
4114 "-S                CAM_DEBUG_SUBTRACE -- internal routine command flow\n"
4115 "-c                CAM_DEBUG_CDB -- print out SCSI CDBs only\n"
4116 "tags arguments:\n"
4117 "-N tags           specify the number of tags to use for this device\n"
4118 "-q                be quiet, don't report the number of tags\n"
4119 "-v                report a number of tag-related parameters\n"
4120 "negotiate arguments:\n"
4121 "-a                send a test unit ready after negotiation\n"
4122 "-c                report/set current negotiation settings\n"
4123 "-D <arg>          \"enable\" or \"disable\" disconnection\n"
4124 "-O offset         set command delay offset\n"
4125 "-q                be quiet, don't report anything\n"
4126 "-R syncrate       synchronization rate in MHz\n"
4127 "-T <arg>          \"enable\" or \"disable\" tagged queueing\n"
4128 "-U                report/set user negotiation settings\n"
4129 "-W bus_width      set the bus width in bits (8, 16 or 32)\n"
4130 "-v                also print a Path Inquiry CCB for the controller\n"
4131 "format arguments:\n"
4132 "-q                be quiet, don't print status messages\n"
4133 "-r                run in report only mode\n"
4134 "-w                don't send immediate format command\n"
4135 "-y                don't ask any questions\n");
4136 #endif /* MINIMALISTIC */
4137 }
4138
4139 int 
4140 main(int argc, char **argv)
4141 {
4142         int c;
4143         char *device = NULL;
4144         int unit = 0;
4145         struct cam_device *cam_dev = NULL;
4146         int timeout = 0, retry_count = 1;
4147         camcontrol_optret optreturn;
4148         char *tstr;
4149         const char *mainopt = "C:En:t:u:v";
4150         const char *subopt = NULL;
4151         char combinedopt[256];
4152         int error = 0, optstart = 2;
4153         int devopen = 1;
4154 #ifndef MINIMALISTIC
4155         int bus, target, lun;
4156 #endif /* MINIMALISTIC */
4157
4158         cmdlist = CAM_CMD_NONE;
4159         arglist = CAM_ARG_NONE;
4160
4161         if (argc < 2) {
4162                 usage(0);
4163                 exit(1);
4164         }
4165
4166         /*
4167          * Get the base option.
4168          */
4169         optreturn = getoption(argv[1], &cmdlist, &arglist, &subopt);
4170
4171         if (optreturn == CC_OR_AMBIGUOUS) {
4172                 warnx("ambiguous option %s", argv[1]);
4173                 usage(0);
4174                 exit(1);
4175         } else if (optreturn == CC_OR_NOT_FOUND) {
4176                 warnx("option %s not found", argv[1]);
4177                 usage(0);
4178                 exit(1);
4179         }
4180
4181         /*
4182          * Ahh, getopt(3) is a pain.
4183          *
4184          * This is a gross hack.  There really aren't many other good
4185          * options (excuse the pun) for parsing options in a situation like
4186          * this.  getopt is kinda braindead, so you end up having to run
4187          * through the options twice, and give each invocation of getopt
4188          * the option string for the other invocation.
4189          * 
4190          * You would think that you could just have two groups of options.
4191          * The first group would get parsed by the first invocation of
4192          * getopt, and the second group would get parsed by the second
4193          * invocation of getopt.  It doesn't quite work out that way.  When
4194          * the first invocation of getopt finishes, it leaves optind pointing
4195          * to the argument _after_ the first argument in the second group.
4196          * So when the second invocation of getopt comes around, it doesn't
4197          * recognize the first argument it gets and then bails out.
4198          * 
4199          * A nice alternative would be to have a flag for getopt that says
4200          * "just keep parsing arguments even when you encounter an unknown
4201          * argument", but there isn't one.  So there's no real clean way to
4202          * easily parse two sets of arguments without having one invocation
4203          * of getopt know about the other.
4204          * 
4205          * Without this hack, the first invocation of getopt would work as
4206          * long as the generic arguments are first, but the second invocation
4207          * (in the subfunction) would fail in one of two ways.  In the case
4208          * where you don't set optreset, it would fail because optind may be
4209          * pointing to the argument after the one it should be pointing at.
4210          * In the case where you do set optreset, and reset optind, it would
4211          * fail because getopt would run into the first set of options, which
4212          * it doesn't understand.
4213          *
4214          * All of this would "sort of" work if you could somehow figure out
4215          * whether optind had been incremented one option too far.  The
4216          * mechanics of that, however, are more daunting than just giving
4217          * both invocations all of the expect options for either invocation.
4218          * 
4219          * Needless to say, I wouldn't mind if someone invented a better
4220          * (non-GPL!) command line parsing interface than getopt.  I
4221          * wouldn't mind if someone added more knobs to getopt to make it
4222          * work better.  Who knows, I may talk myself into doing it someday,
4223          * if the standards weenies let me.  As it is, it just leads to
4224          * hackery like this and causes people to avoid it in some cases.
4225          * 
4226          * KDM, September 8th, 1998
4227          */
4228         if (subopt != NULL)
4229                 sprintf(combinedopt, "%s%s", mainopt, subopt);
4230         else
4231                 sprintf(combinedopt, "%s", mainopt);
4232
4233         /*
4234          * For these options we do not parse optional device arguments and
4235          * we do not open a passthrough device.
4236          */
4237         if ((cmdlist == CAM_CMD_RESCAN)
4238          || (cmdlist == CAM_CMD_RESET)
4239          || (cmdlist == CAM_CMD_DEVTREE)
4240          || (cmdlist == CAM_CMD_USAGE)
4241          || (cmdlist == CAM_CMD_DEBUG))
4242                 devopen = 0;
4243
4244 #ifndef MINIMALISTIC
4245         if ((devopen == 1)
4246          && (argc > 2 && argv[2][0] != '-')) {
4247                 char name[30];
4248                 int rv;
4249
4250                 /*
4251                  * First catch people who try to do things like:
4252                  * camcontrol tur /dev/da0 
4253                  * camcontrol doesn't take device nodes as arguments.
4254                  */
4255                 if (argv[2][0] == '/') {
4256                         warnx("%s is not a valid device identifier", argv[2]);
4257                         errx(1, "please read the camcontrol(8) man page");
4258                 } else if (isdigit(argv[2][0])) {
4259                         /* device specified as bus:target[:lun] */
4260                         rv = parse_btl(argv[2], &bus, &target, &lun, &arglist);
4261                         if (rv < 2)
4262                                 errx(1, "numeric device specification must "
4263                                      "be either bus:target, or "
4264                                      "bus:target:lun");
4265                         /* default to 0 if lun was not specified */
4266                         if ((arglist & CAM_ARG_LUN) == 0) {
4267                                 lun = 0;
4268                                 arglist |= CAM_ARG_LUN;
4269                         }
4270                         optstart++;
4271                 } else {
4272                         if (cam_get_device(argv[2], name, sizeof name, &unit)
4273                             == -1)
4274                                 errx(1, "%s", cam_errbuf);
4275                         device = strdup(name);
4276                         arglist |= CAM_ARG_DEVICE | CAM_ARG_UNIT;
4277                         optstart++;
4278                 }
4279         }
4280 #endif /* MINIMALISTIC */
4281         /*
4282          * Start getopt processing at argv[2/3], since we've already
4283          * accepted argv[1..2] as the command name, and as a possible
4284          * device name.
4285          */
4286         optind = optstart;
4287
4288         /*
4289          * Now we run through the argument list looking for generic
4290          * options, and ignoring options that possibly belong to
4291          * subfunctions.
4292          */
4293         while ((c = getopt(argc, argv, combinedopt))!= -1){
4294                 switch(c) {
4295                         case 'C':
4296                                 retry_count = strtol(optarg, NULL, 0);
4297                                 if (retry_count < 0)
4298                                         errx(1, "retry count %d is < 0",
4299                                              retry_count);
4300                                 arglist |= CAM_ARG_RETRIES;
4301                                 break;
4302                         case 'E':
4303                                 arglist |= CAM_ARG_ERR_RECOVER;
4304                                 break;
4305                         case 'n':
4306                                 arglist |= CAM_ARG_DEVICE;
4307                                 tstr = optarg;
4308                                 while (isspace(*tstr) && (*tstr != '\0'))
4309                                         tstr++;
4310                                 device = (char *)strdup(tstr);
4311                                 break;
4312                         case 't':
4313                                 timeout = strtol(optarg, NULL, 0);
4314                                 if (timeout < 0)
4315                                         errx(1, "invalid timeout %d", timeout);
4316                                 /* Convert the timeout from seconds to ms */
4317                                 timeout *= 1000;
4318                                 arglist |= CAM_ARG_TIMEOUT;
4319                                 break;
4320                         case 'u':
4321                                 arglist |= CAM_ARG_UNIT;
4322                                 unit = strtol(optarg, NULL, 0);
4323                                 break;
4324                         case 'v':
4325                                 arglist |= CAM_ARG_VERBOSE;
4326                                 break;
4327                         default:
4328                                 break;
4329                 }
4330         }
4331
4332 #ifndef MINIMALISTIC
4333         /*
4334          * For most commands we'll want to open the passthrough device
4335          * associated with the specified device.  In the case of the rescan
4336          * commands, we don't use a passthrough device at all, just the
4337          * transport layer device.
4338          */
4339         if (devopen == 1) {
4340                 if (((arglist & (CAM_ARG_BUS|CAM_ARG_TARGET)) == 0)
4341                  && (((arglist & CAM_ARG_DEVICE) == 0)
4342                   || ((arglist & CAM_ARG_UNIT) == 0))) {
4343                         errx(1, "subcommand \"%s\" requires a valid device "
4344                              "identifier", argv[1]);
4345                 }
4346
4347                 if ((cam_dev = ((arglist & (CAM_ARG_BUS | CAM_ARG_TARGET))?
4348                                 cam_open_btl(bus, target, lun, O_RDWR, NULL) :
4349                                 cam_open_spec_device(device,unit,O_RDWR,NULL)))
4350                      == NULL)
4351                         errx(1,"%s", cam_errbuf);
4352         }
4353 #endif /* MINIMALISTIC */
4354
4355         /*
4356          * Reset optind to 2, and reset getopt, so these routines can parse
4357          * the arguments again.
4358          */
4359         optind = optstart;
4360         optreset = 1;
4361
4362         switch(cmdlist) {
4363 #ifndef MINIMALISTIC
4364                 case CAM_CMD_DEVLIST:
4365                         error = getdevlist(cam_dev);
4366                         break;
4367 #endif /* MINIMALISTIC */
4368                 case CAM_CMD_DEVTREE:
4369                         error = getdevtree();
4370                         break;
4371 #ifndef MINIMALISTIC
4372                 case CAM_CMD_TUR:
4373                         error = testunitready(cam_dev, retry_count, timeout, 0);
4374                         break;
4375                 case CAM_CMD_INQUIRY:
4376                         error = scsidoinquiry(cam_dev, argc, argv, combinedopt,
4377                                               retry_count, timeout);
4378                         break;
4379                 case CAM_CMD_IDENTIFY:
4380                         error = ataidentify(cam_dev, retry_count, timeout);
4381                         break;
4382                 case CAM_CMD_STARTSTOP:
4383                         error = scsistart(cam_dev, arglist & CAM_ARG_START_UNIT,
4384                                           arglist & CAM_ARG_EJECT, retry_count,
4385                                           timeout);
4386                         break;
4387 #endif /* MINIMALISTIC */
4388                 case CAM_CMD_RESCAN:
4389                         error = dorescan_or_reset(argc, argv, 1);
4390                         break;
4391                 case CAM_CMD_RESET:
4392                         error = dorescan_or_reset(argc, argv, 0);
4393                         break;
4394 #ifndef MINIMALISTIC
4395                 case CAM_CMD_READ_DEFECTS:
4396                         error = readdefects(cam_dev, argc, argv, combinedopt,
4397                                             retry_count, timeout);
4398                         break;
4399                 case CAM_CMD_MODE_PAGE:
4400                         modepage(cam_dev, argc, argv, combinedopt,
4401                                  retry_count, timeout);
4402                         break;
4403                 case CAM_CMD_SCSI_CMD:
4404                         error = scsicmd(cam_dev, argc, argv, combinedopt,
4405                                         retry_count, timeout);
4406                         break;
4407                 case CAM_CMD_DEBUG:
4408                         error = camdebug(argc, argv, combinedopt);
4409                         break;
4410                 case CAM_CMD_TAG:
4411                         error = tagcontrol(cam_dev, argc, argv, combinedopt);
4412                         break;
4413                 case CAM_CMD_RATE:
4414                         error = ratecontrol(cam_dev, retry_count, timeout,
4415                                             argc, argv, combinedopt);
4416                         break;
4417                 case CAM_CMD_FORMAT:
4418                         error = scsiformat(cam_dev, argc, argv,
4419                                            combinedopt, retry_count, timeout);
4420                         break;
4421                 case CAM_CMD_REPORTLUNS:
4422                         error = scsireportluns(cam_dev, argc, argv,
4423                                                combinedopt, retry_count,
4424                                                timeout);
4425                         break;
4426                 case CAM_CMD_READCAP:
4427                         error = scsireadcapacity(cam_dev, argc, argv,
4428                                                  combinedopt, retry_count,
4429                                                  timeout);
4430                         break;
4431 #endif /* MINIMALISTIC */
4432                 case CAM_CMD_USAGE:
4433                         usage(1);
4434                         break;
4435                 default:
4436                         usage(0);
4437                         error = 1;
4438                         break;
4439         }
4440
4441         if (cam_dev != NULL)
4442                 cam_close_device(cam_dev);
4443
4444         exit(error);
4445 }