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