]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - sbin/camcontrol/camcontrol.c
Merge the firmware download functionality into camcontrol, as well as
[FreeBSD/stable/9.git] / sbin / camcontrol / camcontrol.c
1 /*
2  * Copyright (c) 1997-2007 Kenneth D. Merry
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/ioctl.h>
33 #include <sys/stdint.h>
34 #include <sys/types.h>
35 #include <sys/endian.h>
36 #include <sys/sbuf.h>
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <inttypes.h>
43 #include <limits.h>
44 #include <fcntl.h>
45 #include <ctype.h>
46 #include <err.h>
47 #include <libutil.h>
48
49 #include <cam/cam.h>
50 #include <cam/cam_debug.h>
51 #include <cam/cam_ccb.h>
52 #include <cam/scsi/scsi_all.h>
53 #include <cam/scsi/scsi_da.h>
54 #include <cam/scsi/scsi_pass.h>
55 #include <cam/scsi/scsi_message.h>
56 #include <cam/scsi/smp_all.h>
57 #include <cam/ata/ata_all.h>
58 #include <camlib.h>
59 #include "camcontrol.h"
60
61 typedef enum {
62         CAM_CMD_NONE            = 0x00000000,
63         CAM_CMD_DEVLIST         = 0x00000001,
64         CAM_CMD_TUR             = 0x00000002,
65         CAM_CMD_INQUIRY         = 0x00000003,
66         CAM_CMD_STARTSTOP       = 0x00000004,
67         CAM_CMD_RESCAN          = 0x00000005,
68         CAM_CMD_READ_DEFECTS    = 0x00000006,
69         CAM_CMD_MODE_PAGE       = 0x00000007,
70         CAM_CMD_SCSI_CMD        = 0x00000008,
71         CAM_CMD_DEVTREE         = 0x00000009,
72         CAM_CMD_USAGE           = 0x0000000a,
73         CAM_CMD_DEBUG           = 0x0000000b,
74         CAM_CMD_RESET           = 0x0000000c,
75         CAM_CMD_FORMAT          = 0x0000000d,
76         CAM_CMD_TAG             = 0x0000000e,
77         CAM_CMD_RATE            = 0x0000000f,
78         CAM_CMD_DETACH          = 0x00000010,
79         CAM_CMD_REPORTLUNS      = 0x00000011,
80         CAM_CMD_READCAP         = 0x00000012,
81         CAM_CMD_IDENTIFY        = 0x00000013,
82         CAM_CMD_IDLE            = 0x00000014,
83         CAM_CMD_STANDBY         = 0x00000015,
84         CAM_CMD_SLEEP           = 0x00000016,
85         CAM_CMD_SMP_CMD         = 0x00000017,
86         CAM_CMD_SMP_RG          = 0x00000018,
87         CAM_CMD_SMP_PC          = 0x00000019,
88         CAM_CMD_SMP_PHYLIST     = 0x0000001a,
89         CAM_CMD_SMP_MANINFO     = 0x0000001b,
90         CAM_CMD_DOWNLOAD_FW     = 0x0000001c
91 } cam_cmdmask;
92
93 typedef enum {
94         CAM_ARG_NONE            = 0x00000000,
95         CAM_ARG_VERBOSE         = 0x00000001,
96         CAM_ARG_DEVICE          = 0x00000002,
97         CAM_ARG_BUS             = 0x00000004,
98         CAM_ARG_TARGET          = 0x00000008,
99         CAM_ARG_LUN             = 0x00000010,
100         CAM_ARG_EJECT           = 0x00000020,
101         CAM_ARG_UNIT            = 0x00000040,
102         CAM_ARG_FORMAT_BLOCK    = 0x00000080,
103         CAM_ARG_FORMAT_BFI      = 0x00000100,
104         CAM_ARG_FORMAT_PHYS     = 0x00000200,
105         CAM_ARG_PLIST           = 0x00000400,
106         CAM_ARG_GLIST           = 0x00000800,
107         CAM_ARG_GET_SERIAL      = 0x00001000,
108         CAM_ARG_GET_STDINQ      = 0x00002000,
109         CAM_ARG_GET_XFERRATE    = 0x00004000,
110         CAM_ARG_INQ_MASK        = 0x00007000,
111         CAM_ARG_MODE_EDIT       = 0x00008000,
112         CAM_ARG_PAGE_CNTL       = 0x00010000,
113         CAM_ARG_TIMEOUT         = 0x00020000,
114         CAM_ARG_CMD_IN          = 0x00040000,
115         CAM_ARG_CMD_OUT         = 0x00080000,
116         CAM_ARG_DBD             = 0x00100000,
117         CAM_ARG_ERR_RECOVER     = 0x00200000,
118         CAM_ARG_RETRIES         = 0x00400000,
119         CAM_ARG_START_UNIT      = 0x00800000,
120         CAM_ARG_DEBUG_INFO      = 0x01000000,
121         CAM_ARG_DEBUG_TRACE     = 0x02000000,
122         CAM_ARG_DEBUG_SUBTRACE  = 0x04000000,
123         CAM_ARG_DEBUG_CDB       = 0x08000000,
124         CAM_ARG_DEBUG_XPT       = 0x10000000,
125         CAM_ARG_DEBUG_PERIPH    = 0x20000000,
126         CAM_ARG_DEBUG_PROBE     = 0x40000000,
127 } cam_argmask;
128
129 struct camcontrol_opts {
130         const char      *optname;
131         uint32_t        cmdnum;
132         cam_argmask     argnum;
133         const char      *subopt;
134 };
135
136 #ifndef MINIMALISTIC
137 static const char scsicmd_opts[] = "a:c:dfi:o:r";
138 static const char readdefect_opts[] = "f:GP";
139 static const char negotiate_opts[] = "acD:M:O:qR:T:UW:";
140 static const char smprg_opts[] = "l";
141 static const char smppc_opts[] = "a:A:d:lm:M:o:p:s:S:T:";
142 static const char smpphylist_opts[] = "lq";
143 #endif
144
145 struct camcontrol_opts option_table[] = {
146 #ifndef MINIMALISTIC
147         {"tur", CAM_CMD_TUR, CAM_ARG_NONE, NULL},
148         {"inquiry", CAM_CMD_INQUIRY, CAM_ARG_NONE, "DSR"},
149         {"identify", CAM_CMD_IDENTIFY, CAM_ARG_NONE, NULL},
150         {"start", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT, NULL},
151         {"stop", CAM_CMD_STARTSTOP, CAM_ARG_NONE, NULL},
152         {"load", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT | CAM_ARG_EJECT, NULL},
153         {"eject", CAM_CMD_STARTSTOP, CAM_ARG_EJECT, NULL},
154         {"reportluns", CAM_CMD_REPORTLUNS, CAM_ARG_NONE, "clr:"},
155         {"readcapacity", CAM_CMD_READCAP, CAM_ARG_NONE, "bhHNqs"},
156 #endif /* MINIMALISTIC */
157         {"rescan", CAM_CMD_RESCAN, CAM_ARG_NONE, NULL},
158         {"reset", CAM_CMD_RESET, CAM_ARG_NONE, NULL},
159 #ifndef MINIMALISTIC
160         {"cmd", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts},
161         {"command", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts},
162         {"smpcmd", CAM_CMD_SMP_CMD, CAM_ARG_NONE, "r:R:"},
163         {"smprg", CAM_CMD_SMP_RG, CAM_ARG_NONE, smprg_opts},
164         {"smpreportgeneral", CAM_CMD_SMP_RG, CAM_ARG_NONE, smprg_opts},
165         {"smppc", CAM_CMD_SMP_PC, CAM_ARG_NONE, smppc_opts},
166         {"smpphycontrol", CAM_CMD_SMP_PC, CAM_ARG_NONE, smppc_opts},
167         {"smpplist", CAM_CMD_SMP_PHYLIST, CAM_ARG_NONE, smpphylist_opts},
168         {"smpphylist", CAM_CMD_SMP_PHYLIST, CAM_ARG_NONE, smpphylist_opts},
169         {"smpmaninfo", CAM_CMD_SMP_MANINFO, CAM_ARG_NONE, "l"},
170         {"defects", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts},
171         {"defectlist", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts},
172 #endif /* MINIMALISTIC */
173         {"devlist", CAM_CMD_DEVTREE, CAM_ARG_NONE, NULL},
174 #ifndef MINIMALISTIC
175         {"periphlist", CAM_CMD_DEVLIST, CAM_ARG_NONE, NULL},
176         {"modepage", CAM_CMD_MODE_PAGE, CAM_ARG_NONE, "bdelm:P:"},
177         {"tags", CAM_CMD_TAG, CAM_ARG_NONE, "N:q"},
178         {"negotiate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts},
179         {"rate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts},
180         {"debug", CAM_CMD_DEBUG, CAM_ARG_NONE, "IPTSXcp"},
181         {"format", CAM_CMD_FORMAT, CAM_ARG_NONE, "qrwy"},
182         {"idle", CAM_CMD_IDLE, CAM_ARG_NONE, "t:"},
183         {"standby", CAM_CMD_STANDBY, CAM_ARG_NONE, "t:"},
184         {"sleep", CAM_CMD_SLEEP, CAM_ARG_NONE, ""},
185         {"fwdownload", CAM_CMD_DOWNLOAD_FW, CAM_ARG_NONE, "f:ys"},
186 #endif /* MINIMALISTIC */
187         {"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
188         {"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
189         {"-h", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
190         {NULL, 0, 0, NULL}
191 };
192
193 typedef enum {
194         CC_OR_NOT_FOUND,
195         CC_OR_AMBIGUOUS,
196         CC_OR_FOUND
197 } camcontrol_optret;
198
199 struct cam_devitem {
200         struct device_match_result dev_match;
201         int num_periphs;
202         struct periph_match_result *periph_matches;
203         struct scsi_vpd_device_id *device_id;
204         int device_id_len;
205         STAILQ_ENTRY(cam_devitem) links;
206 };
207
208 struct cam_devlist {
209         STAILQ_HEAD(, cam_devitem) dev_queue;
210         path_id_t path_id;
211 };
212
213 cam_cmdmask cmdlist;
214 cam_argmask arglist;
215
216 camcontrol_optret getoption(struct camcontrol_opts *table, char *arg,
217                             uint32_t *cmdnum, cam_argmask *argnum,
218                             const char **subopt);
219 #ifndef MINIMALISTIC
220 static int getdevlist(struct cam_device *device);
221 #endif /* MINIMALISTIC */
222 static int getdevtree(void);
223 #ifndef MINIMALISTIC
224 static int testunitready(struct cam_device *device, int retry_count,
225                          int timeout, int quiet);
226 static int scsistart(struct cam_device *device, int startstop, int loadeject,
227                      int retry_count, int timeout);
228 static int scsiinquiry(struct cam_device *device, int retry_count, int timeout);
229 static int scsiserial(struct cam_device *device, int retry_count, int timeout);
230 static int camxferrate(struct cam_device *device);
231 #endif /* MINIMALISTIC */
232 static int parse_btl(char *tstr, int *bus, int *target, int *lun,
233                      cam_argmask *arglst);
234 static int dorescan_or_reset(int argc, char **argv, int rescan);
235 static int rescan_or_reset_bus(int bus, int rescan);
236 static int scanlun_or_reset_dev(int bus, int target, int lun, int scan);
237 #ifndef MINIMALISTIC
238 static int readdefects(struct cam_device *device, int argc, char **argv,
239                        char *combinedopt, int retry_count, int timeout);
240 static void modepage(struct cam_device *device, int argc, char **argv,
241                      char *combinedopt, int retry_count, int timeout);
242 static int scsicmd(struct cam_device *device, int argc, char **argv,
243                    char *combinedopt, int retry_count, int timeout);
244 static int smpcmd(struct cam_device *device, int argc, char **argv,
245                   char *combinedopt, int retry_count, int timeout);
246 static int smpreportgeneral(struct cam_device *device, int argc, char **argv,
247                             char *combinedopt, int retry_count, int timeout);
248 static int smpphycontrol(struct cam_device *device, int argc, char **argv,
249                          char *combinedopt, int retry_count, int timeout);
250 static int smpmaninfo(struct cam_device *device, int argc, char **argv,
251                       char *combinedopt, int retry_count, int timeout);
252 static int getdevid(struct cam_devitem *item);
253 static int buildbusdevlist(struct cam_devlist *devlist);
254 static void freebusdevlist(struct cam_devlist *devlist);
255 static struct cam_devitem *findsasdevice(struct cam_devlist *devlist,
256                                          uint64_t sasaddr);
257 static int smpphylist(struct cam_device *device, int argc, char **argv,
258                       char *combinedopt, int retry_count, int timeout);
259 static int tagcontrol(struct cam_device *device, int argc, char **argv,
260                       char *combinedopt);
261 static void cts_print(struct cam_device *device,
262                       struct ccb_trans_settings *cts);
263 static void cpi_print(struct ccb_pathinq *cpi);
264 static int get_cpi(struct cam_device *device, struct ccb_pathinq *cpi);
265 static int get_cgd(struct cam_device *device, struct ccb_getdev *cgd);
266 static int get_print_cts(struct cam_device *device, int user_settings,
267                          int quiet, struct ccb_trans_settings *cts);
268 static int ratecontrol(struct cam_device *device, int retry_count,
269                        int timeout, int argc, char **argv, char *combinedopt);
270 static int scsiformat(struct cam_device *device, int argc, char **argv,
271                       char *combinedopt, int retry_count, int timeout);
272 static int scsireportluns(struct cam_device *device, int argc, char **argv,
273                           char *combinedopt, int retry_count, int timeout);
274 static int scsireadcapacity(struct cam_device *device, int argc, char **argv,
275                             char *combinedopt, int retry_count, int timeout);
276 static int atapm(struct cam_device *device, int argc, char **argv,
277                             char *combinedopt, int retry_count, int timeout);
278 #endif /* MINIMALISTIC */
279 #ifndef min
280 #define min(a,b) (((a)<(b))?(a):(b))
281 #endif
282 #ifndef max
283 #define max(a,b) (((a)>(b))?(a):(b))
284 #endif
285
286 camcontrol_optret
287 getoption(struct camcontrol_opts *table, char *arg, uint32_t *cmdnum,
288           cam_argmask *argnum, const char **subopt)
289 {
290         struct camcontrol_opts *opts;
291         int num_matches = 0;
292
293         for (opts = table; (opts != NULL) && (opts->optname != NULL);
294              opts++) {
295                 if (strncmp(opts->optname, arg, strlen(arg)) == 0) {
296                         *cmdnum = opts->cmdnum;
297                         *argnum = opts->argnum;
298                         *subopt = opts->subopt;
299                         if (++num_matches > 1)
300                                 return(CC_OR_AMBIGUOUS);
301                 }
302         }
303
304         if (num_matches > 0)
305                 return(CC_OR_FOUND);
306         else
307                 return(CC_OR_NOT_FOUND);
308 }
309
310 #ifndef MINIMALISTIC
311 static int
312 getdevlist(struct cam_device *device)
313 {
314         union ccb *ccb;
315         char status[32];
316         int error = 0;
317
318         ccb = cam_getccb(device);
319
320         ccb->ccb_h.func_code = XPT_GDEVLIST;
321         ccb->ccb_h.flags = CAM_DIR_NONE;
322         ccb->ccb_h.retry_count = 1;
323         ccb->cgdl.index = 0;
324         ccb->cgdl.status = CAM_GDEVLIST_MORE_DEVS;
325         while (ccb->cgdl.status == CAM_GDEVLIST_MORE_DEVS) {
326                 if (cam_send_ccb(device, ccb) < 0) {
327                         perror("error getting device list");
328                         cam_freeccb(ccb);
329                         return(1);
330                 }
331
332                 status[0] = '\0';
333
334                 switch (ccb->cgdl.status) {
335                         case CAM_GDEVLIST_MORE_DEVS:
336                                 strcpy(status, "MORE");
337                                 break;
338                         case CAM_GDEVLIST_LAST_DEVICE:
339                                 strcpy(status, "LAST");
340                                 break;
341                         case CAM_GDEVLIST_LIST_CHANGED:
342                                 strcpy(status, "CHANGED");
343                                 break;
344                         case CAM_GDEVLIST_ERROR:
345                                 strcpy(status, "ERROR");
346                                 error = 1;
347                                 break;
348                 }
349
350                 fprintf(stdout, "%s%d:  generation: %d index: %d status: %s\n",
351                         ccb->cgdl.periph_name,
352                         ccb->cgdl.unit_number,
353                         ccb->cgdl.generation,
354                         ccb->cgdl.index,
355                         status);
356
357                 /*
358                  * If the list has changed, we need to start over from the
359                  * beginning.
360                  */
361                 if (ccb->cgdl.status == CAM_GDEVLIST_LIST_CHANGED)
362                         ccb->cgdl.index = 0;
363         }
364
365         cam_freeccb(ccb);
366
367         return(error);
368 }
369 #endif /* MINIMALISTIC */
370
371 static int
372 getdevtree(void)
373 {
374         union ccb ccb;
375         int bufsize, fd;
376         unsigned int i;
377         int need_close = 0;
378         int error = 0;
379         int skip_device = 0;
380
381         if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
382                 warn("couldn't open %s", XPT_DEVICE);
383                 return(1);
384         }
385
386         bzero(&ccb, sizeof(union ccb));
387
388         ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
389         ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
390         ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
391
392         ccb.ccb_h.func_code = XPT_DEV_MATCH;
393         bufsize = sizeof(struct dev_match_result) * 100;
394         ccb.cdm.match_buf_len = bufsize;
395         ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
396         if (ccb.cdm.matches == NULL) {
397                 warnx("can't malloc memory for matches");
398                 close(fd);
399                 return(1);
400         }
401         ccb.cdm.num_matches = 0;
402
403         /*
404          * We fetch all nodes, since we display most of them in the default
405          * case, and all in the verbose case.
406          */
407         ccb.cdm.num_patterns = 0;
408         ccb.cdm.pattern_buf_len = 0;
409
410         /*
411          * We do the ioctl multiple times if necessary, in case there are
412          * more than 100 nodes in the EDT.
413          */
414         do {
415                 if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
416                         warn("error sending CAMIOCOMMAND ioctl");
417                         error = 1;
418                         break;
419                 }
420
421                 if ((ccb.ccb_h.status != CAM_REQ_CMP)
422                  || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
423                     && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
424                         warnx("got CAM error %#x, CDM error %d\n",
425                               ccb.ccb_h.status, ccb.cdm.status);
426                         error = 1;
427                         break;
428                 }
429
430                 for (i = 0; i < ccb.cdm.num_matches; i++) {
431                         switch (ccb.cdm.matches[i].type) {
432                         case DEV_MATCH_BUS: {
433                                 struct bus_match_result *bus_result;
434
435                                 /*
436                                  * Only print the bus information if the
437                                  * user turns on the verbose flag.
438                                  */
439                                 if ((arglist & CAM_ARG_VERBOSE) == 0)
440                                         break;
441
442                                 bus_result =
443                                         &ccb.cdm.matches[i].result.bus_result;
444
445                                 if (need_close) {
446                                         fprintf(stdout, ")\n");
447                                         need_close = 0;
448                                 }
449
450                                 fprintf(stdout, "scbus%d on %s%d bus %d:\n",
451                                         bus_result->path_id,
452                                         bus_result->dev_name,
453                                         bus_result->unit_number,
454                                         bus_result->bus_id);
455                                 break;
456                         }
457                         case DEV_MATCH_DEVICE: {
458                                 struct device_match_result *dev_result;
459                                 char vendor[16], product[48], revision[16];
460                                 char fw[5], tmpstr[256];
461
462                                 dev_result =
463                                      &ccb.cdm.matches[i].result.device_result;
464
465                                 if ((dev_result->flags
466                                      & DEV_RESULT_UNCONFIGURED)
467                                  && ((arglist & CAM_ARG_VERBOSE) == 0)) {
468                                         skip_device = 1;
469                                         break;
470                                 } else
471                                         skip_device = 0;
472
473                                 if (dev_result->protocol == PROTO_SCSI) {
474                                     cam_strvis(vendor, dev_result->inq_data.vendor,
475                                            sizeof(dev_result->inq_data.vendor),
476                                            sizeof(vendor));
477                                     cam_strvis(product,
478                                            dev_result->inq_data.product,
479                                            sizeof(dev_result->inq_data.product),
480                                            sizeof(product));
481                                     cam_strvis(revision,
482                                            dev_result->inq_data.revision,
483                                           sizeof(dev_result->inq_data.revision),
484                                            sizeof(revision));
485                                     sprintf(tmpstr, "<%s %s %s>", vendor, product,
486                                         revision);
487                                 } else if (dev_result->protocol == PROTO_ATA ||
488                                     dev_result->protocol == PROTO_SATAPM) {
489                                     cam_strvis(product,
490                                            dev_result->ident_data.model,
491                                            sizeof(dev_result->ident_data.model),
492                                            sizeof(product));
493                                     cam_strvis(revision,
494                                            dev_result->ident_data.revision,
495                                           sizeof(dev_result->ident_data.revision),
496                                            sizeof(revision));
497                                     sprintf(tmpstr, "<%s %s>", product,
498                                         revision);
499                                 } else if (dev_result->protocol == PROTO_SEMB) {
500                                         struct sep_identify_data *sid;
501
502                                         sid = (struct sep_identify_data *)
503                                             &dev_result->ident_data;
504                                         cam_strvis(vendor, sid->vendor_id,
505                                             sizeof(sid->vendor_id),
506                                             sizeof(vendor));
507                                         cam_strvis(product, sid->product_id,
508                                             sizeof(sid->product_id),
509                                             sizeof(product));
510                                         cam_strvis(revision, sid->product_rev,
511                                             sizeof(sid->product_rev),
512                                             sizeof(revision));
513                                         cam_strvis(fw, sid->firmware_rev,
514                                             sizeof(sid->firmware_rev),
515                                             sizeof(fw));
516                                         sprintf(tmpstr, "<%s %s %s %s>",
517                                             vendor, product, revision, fw);
518                                 } else {
519                                     sprintf(tmpstr, "<>");
520                                 }
521                                 if (need_close) {
522                                         fprintf(stdout, ")\n");
523                                         need_close = 0;
524                                 }
525
526                                 fprintf(stdout, "%-33s  at scbus%d "
527                                         "target %d lun %d (",
528                                         tmpstr,
529                                         dev_result->path_id,
530                                         dev_result->target_id,
531                                         dev_result->target_lun);
532
533                                 need_close = 1;
534
535                                 break;
536                         }
537                         case DEV_MATCH_PERIPH: {
538                                 struct periph_match_result *periph_result;
539
540                                 periph_result =
541                                       &ccb.cdm.matches[i].result.periph_result;
542
543                                 if (skip_device != 0)
544                                         break;
545
546                                 if (need_close > 1)
547                                         fprintf(stdout, ",");
548
549                                 fprintf(stdout, "%s%d",
550                                         periph_result->periph_name,
551                                         periph_result->unit_number);
552
553                                 need_close++;
554                                 break;
555                         }
556                         default:
557                                 fprintf(stdout, "unknown match type\n");
558                                 break;
559                         }
560                 }
561
562         } while ((ccb.ccb_h.status == CAM_REQ_CMP)
563                 && (ccb.cdm.status == CAM_DEV_MATCH_MORE));
564
565         if (need_close)
566                 fprintf(stdout, ")\n");
567
568         close(fd);
569
570         return(error);
571 }
572
573 #ifndef MINIMALISTIC
574 static int
575 testunitready(struct cam_device *device, int retry_count, int timeout,
576               int quiet)
577 {
578         int error = 0;
579         union ccb *ccb;
580
581         ccb = cam_getccb(device);
582
583         scsi_test_unit_ready(&ccb->csio,
584                              /* retries */ retry_count,
585                              /* cbfcnp */ NULL,
586                              /* tag_action */ MSG_SIMPLE_Q_TAG,
587                              /* sense_len */ SSD_FULL_SIZE,
588                              /* timeout */ timeout ? timeout : 5000);
589
590         /* Disable freezing the device queue */
591         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
592
593         if (arglist & CAM_ARG_ERR_RECOVER)
594                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
595
596         if (cam_send_ccb(device, ccb) < 0) {
597                 if (quiet == 0)
598                         perror("error sending test unit ready");
599
600                 if (arglist & CAM_ARG_VERBOSE) {
601                         cam_error_print(device, ccb, CAM_ESF_ALL,
602                                         CAM_EPF_ALL, stderr);
603                 }
604
605                 cam_freeccb(ccb);
606                 return(1);
607         }
608
609         if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
610                 if (quiet == 0)
611                         fprintf(stdout, "Unit is ready\n");
612         } else {
613                 if (quiet == 0)
614                         fprintf(stdout, "Unit is not ready\n");
615                 error = 1;
616
617                 if (arglist & CAM_ARG_VERBOSE) {
618                         cam_error_print(device, ccb, CAM_ESF_ALL,
619                                         CAM_EPF_ALL, stderr);
620                 }
621         }
622
623         cam_freeccb(ccb);
624
625         return(error);
626 }
627
628 static int
629 scsistart(struct cam_device *device, int startstop, int loadeject,
630           int retry_count, int timeout)
631 {
632         union ccb *ccb;
633         int error = 0;
634
635         ccb = cam_getccb(device);
636
637         /*
638          * If we're stopping, send an ordered tag so the drive in question
639          * will finish any previously queued writes before stopping.  If
640          * the device isn't capable of tagged queueing, or if tagged
641          * queueing is turned off, the tag action is a no-op.
642          */
643         scsi_start_stop(&ccb->csio,
644                         /* retries */ retry_count,
645                         /* cbfcnp */ NULL,
646                         /* tag_action */ startstop ? MSG_SIMPLE_Q_TAG :
647                                                      MSG_ORDERED_Q_TAG,
648                         /* start/stop */ startstop,
649                         /* load_eject */ loadeject,
650                         /* immediate */ 0,
651                         /* sense_len */ SSD_FULL_SIZE,
652                         /* timeout */ timeout ? timeout : 120000);
653
654         /* Disable freezing the device queue */
655         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
656
657         if (arglist & CAM_ARG_ERR_RECOVER)
658                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
659
660         if (cam_send_ccb(device, ccb) < 0) {
661                 perror("error sending start unit");
662
663                 if (arglist & CAM_ARG_VERBOSE) {
664                         cam_error_print(device, ccb, CAM_ESF_ALL,
665                                         CAM_EPF_ALL, stderr);
666                 }
667
668                 cam_freeccb(ccb);
669                 return(1);
670         }
671
672         if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
673                 if (startstop) {
674                         fprintf(stdout, "Unit started successfully");
675                         if (loadeject)
676                                 fprintf(stdout,", Media loaded\n");
677                         else
678                                 fprintf(stdout,"\n");
679                 } else {
680                         fprintf(stdout, "Unit stopped successfully");
681                         if (loadeject)
682                                 fprintf(stdout, ", Media ejected\n");
683                         else
684                                 fprintf(stdout, "\n");
685                 }
686         else {
687                 error = 1;
688                 if (startstop)
689                         fprintf(stdout,
690                                 "Error received from start unit command\n");
691                 else
692                         fprintf(stdout,
693                                 "Error received from stop unit command\n");
694
695                 if (arglist & CAM_ARG_VERBOSE) {
696                         cam_error_print(device, ccb, CAM_ESF_ALL,
697                                         CAM_EPF_ALL, stderr);
698                 }
699         }
700
701         cam_freeccb(ccb);
702
703         return(error);
704 }
705
706 int
707 scsidoinquiry(struct cam_device *device, int argc, char **argv,
708               char *combinedopt, int retry_count, int timeout)
709 {
710         int c;
711         int error = 0;
712
713         while ((c = getopt(argc, argv, combinedopt)) != -1) {
714                 switch(c) {
715                 case 'D':
716                         arglist |= CAM_ARG_GET_STDINQ;
717                         break;
718                 case 'R':
719                         arglist |= CAM_ARG_GET_XFERRATE;
720                         break;
721                 case 'S':
722                         arglist |= CAM_ARG_GET_SERIAL;
723                         break;
724                 default:
725                         break;
726                 }
727         }
728
729         /*
730          * If the user didn't specify any inquiry options, he wants all of
731          * them.
732          */
733         if ((arglist & CAM_ARG_INQ_MASK) == 0)
734                 arglist |= CAM_ARG_INQ_MASK;
735
736         if (arglist & CAM_ARG_GET_STDINQ)
737                 error = scsiinquiry(device, retry_count, timeout);
738
739         if (error != 0)
740                 return(error);
741
742         if (arglist & CAM_ARG_GET_SERIAL)
743                 scsiserial(device, retry_count, timeout);
744
745         if (error != 0)
746                 return(error);
747
748         if (arglist & CAM_ARG_GET_XFERRATE)
749                 error = camxferrate(device);
750
751         return(error);
752 }
753
754 static int
755 scsiinquiry(struct cam_device *device, int retry_count, int timeout)
756 {
757         union ccb *ccb;
758         struct scsi_inquiry_data *inq_buf;
759         int error = 0;
760
761         ccb = cam_getccb(device);
762
763         if (ccb == NULL) {
764                 warnx("couldn't allocate CCB");
765                 return(1);
766         }
767
768         /* cam_getccb cleans up the header, caller has to zero the payload */
769         bzero(&(&ccb->ccb_h)[1],
770               sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
771
772         inq_buf = (struct scsi_inquiry_data *)malloc(
773                 sizeof(struct scsi_inquiry_data));
774
775         if (inq_buf == NULL) {
776                 cam_freeccb(ccb);
777                 warnx("can't malloc memory for inquiry\n");
778                 return(1);
779         }
780         bzero(inq_buf, sizeof(*inq_buf));
781
782         /*
783          * Note that although the size of the inquiry buffer is the full
784          * 256 bytes specified in the SCSI spec, we only tell the device
785          * that we have allocated SHORT_INQUIRY_LENGTH bytes.  There are
786          * two reasons for this:
787          *
788          *  - The SCSI spec says that when a length field is only 1 byte,
789          *    a value of 0 will be interpreted as 256.  Therefore
790          *    scsi_inquiry() will convert an inq_len (which is passed in as
791          *    a u_int32_t, but the field in the CDB is only 1 byte) of 256
792          *    to 0.  Evidently, very few devices meet the spec in that
793          *    regard.  Some devices, like many Seagate disks, take the 0 as
794          *    0, and don't return any data.  One Pioneer DVD-R drive
795          *    returns more data than the command asked for.
796          *
797          *    So, since there are numerous devices that just don't work
798          *    right with the full inquiry size, we don't send the full size.
799          *
800          *  - The second reason not to use the full inquiry data length is
801          *    that we don't need it here.  The only reason we issue a
802          *    standard inquiry is to get the vendor name, device name,
803          *    and revision so scsi_print_inquiry() can print them.
804          *
805          * If, at some point in the future, more inquiry data is needed for
806          * some reason, this code should use a procedure similar to the
807          * probe code.  i.e., issue a short inquiry, and determine from
808          * the additional length passed back from the device how much
809          * inquiry data the device supports.  Once the amount the device
810          * supports is determined, issue an inquiry for that amount and no
811          * more.
812          *
813          * KDM, 2/18/2000
814          */
815         scsi_inquiry(&ccb->csio,
816                      /* retries */ retry_count,
817                      /* cbfcnp */ NULL,
818                      /* tag_action */ MSG_SIMPLE_Q_TAG,
819                      /* inq_buf */ (u_int8_t *)inq_buf,
820                      /* inq_len */ SHORT_INQUIRY_LENGTH,
821                      /* evpd */ 0,
822                      /* page_code */ 0,
823                      /* sense_len */ SSD_FULL_SIZE,
824                      /* timeout */ timeout ? timeout : 5000);
825
826         /* Disable freezing the device queue */
827         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
828
829         if (arglist & CAM_ARG_ERR_RECOVER)
830                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
831
832         if (cam_send_ccb(device, ccb) < 0) {
833                 perror("error sending SCSI inquiry");
834
835                 if (arglist & CAM_ARG_VERBOSE) {
836                         cam_error_print(device, ccb, CAM_ESF_ALL,
837                                         CAM_EPF_ALL, stderr);
838                 }
839
840                 cam_freeccb(ccb);
841                 return(1);
842         }
843
844         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
845                 error = 1;
846
847                 if (arglist & CAM_ARG_VERBOSE) {
848                         cam_error_print(device, ccb, CAM_ESF_ALL,
849                                         CAM_EPF_ALL, stderr);
850                 }
851         }
852
853         cam_freeccb(ccb);
854
855         if (error != 0) {
856                 free(inq_buf);
857                 return(error);
858         }
859
860         fprintf(stdout, "%s%d: ", device->device_name,
861                 device->dev_unit_num);
862         scsi_print_inquiry(inq_buf);
863
864         free(inq_buf);
865
866         return(0);
867 }
868
869 static int
870 scsiserial(struct cam_device *device, int retry_count, int timeout)
871 {
872         union ccb *ccb;
873         struct scsi_vpd_unit_serial_number *serial_buf;
874         char serial_num[SVPD_SERIAL_NUM_SIZE + 1];
875         int error = 0;
876
877         ccb = cam_getccb(device);
878
879         if (ccb == NULL) {
880                 warnx("couldn't allocate CCB");
881                 return(1);
882         }
883
884         /* cam_getccb cleans up the header, caller has to zero the payload */
885         bzero(&(&ccb->ccb_h)[1],
886               sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
887
888         serial_buf = (struct scsi_vpd_unit_serial_number *)
889                 malloc(sizeof(*serial_buf));
890
891         if (serial_buf == NULL) {
892                 cam_freeccb(ccb);
893                 warnx("can't malloc memory for serial number");
894                 return(1);
895         }
896
897         scsi_inquiry(&ccb->csio,
898                      /*retries*/ retry_count,
899                      /*cbfcnp*/ NULL,
900                      /* tag_action */ MSG_SIMPLE_Q_TAG,
901                      /* inq_buf */ (u_int8_t *)serial_buf,
902                      /* inq_len */ sizeof(*serial_buf),
903                      /* evpd */ 1,
904                      /* page_code */ SVPD_UNIT_SERIAL_NUMBER,
905                      /* sense_len */ SSD_FULL_SIZE,
906                      /* timeout */ timeout ? timeout : 5000);
907
908         /* Disable freezing the device queue */
909         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
910
911         if (arglist & CAM_ARG_ERR_RECOVER)
912                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
913
914         if (cam_send_ccb(device, ccb) < 0) {
915                 warn("error getting serial number");
916
917                 if (arglist & CAM_ARG_VERBOSE) {
918                         cam_error_print(device, ccb, CAM_ESF_ALL,
919                                         CAM_EPF_ALL, stderr);
920                 }
921
922                 cam_freeccb(ccb);
923                 free(serial_buf);
924                 return(1);
925         }
926
927         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
928                 error = 1;
929
930                 if (arglist & CAM_ARG_VERBOSE) {
931                         cam_error_print(device, ccb, CAM_ESF_ALL,
932                                         CAM_EPF_ALL, stderr);
933                 }
934         }
935
936         cam_freeccb(ccb);
937
938         if (error != 0) {
939                 free(serial_buf);
940                 return(error);
941         }
942
943         bcopy(serial_buf->serial_num, serial_num, serial_buf->length);
944         serial_num[serial_buf->length] = '\0';
945
946         if ((arglist & CAM_ARG_GET_STDINQ)
947          || (arglist & CAM_ARG_GET_XFERRATE))
948                 fprintf(stdout, "%s%d: Serial Number ",
949                         device->device_name, device->dev_unit_num);
950
951         fprintf(stdout, "%.60s\n", serial_num);
952
953         free(serial_buf);
954
955         return(0);
956 }
957
958 static int
959 camxferrate(struct cam_device *device)
960 {
961         struct ccb_pathinq cpi;
962         u_int32_t freq = 0;
963         u_int32_t speed = 0;
964         union ccb *ccb;
965         u_int mb;
966         int retval = 0;
967
968         if ((retval = get_cpi(device, &cpi)) != 0)
969                 return (1);
970
971         ccb = cam_getccb(device);
972
973         if (ccb == NULL) {
974                 warnx("couldn't allocate CCB");
975                 return(1);
976         }
977
978         bzero(&(&ccb->ccb_h)[1],
979               sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr));
980
981         ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
982         ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS;
983
984         if (((retval = cam_send_ccb(device, ccb)) < 0)
985          || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
986                 const char error_string[] = "error getting transfer settings";
987
988                 if (retval < 0)
989                         warn(error_string);
990                 else
991                         warnx(error_string);
992
993                 if (arglist & CAM_ARG_VERBOSE)
994                         cam_error_print(device, ccb, CAM_ESF_ALL,
995                                         CAM_EPF_ALL, stderr);
996
997                 retval = 1;
998
999                 goto xferrate_bailout;
1000
1001         }
1002
1003         speed = cpi.base_transfer_speed;
1004         freq = 0;
1005         if (ccb->cts.transport == XPORT_SPI) {
1006                 struct ccb_trans_settings_spi *spi =
1007                     &ccb->cts.xport_specific.spi;
1008
1009                 if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) {
1010                         freq = scsi_calc_syncsrate(spi->sync_period);
1011                         speed = freq;
1012                 }
1013                 if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
1014                         speed *= (0x01 << spi->bus_width);
1015                 }
1016         } else if (ccb->cts.transport == XPORT_FC) {
1017                 struct ccb_trans_settings_fc *fc =
1018                     &ccb->cts.xport_specific.fc;
1019
1020                 if (fc->valid & CTS_FC_VALID_SPEED)
1021                         speed = fc->bitrate;
1022         } else if (ccb->cts.transport == XPORT_SAS) {
1023                 struct ccb_trans_settings_sas *sas =
1024                     &ccb->cts.xport_specific.sas;
1025
1026                 if (sas->valid & CTS_SAS_VALID_SPEED)
1027                         speed = sas->bitrate;
1028         } else if (ccb->cts.transport == XPORT_ATA) {
1029                 struct ccb_trans_settings_pata *pata =
1030                     &ccb->cts.xport_specific.ata;
1031
1032                 if (pata->valid & CTS_ATA_VALID_MODE)
1033                         speed = ata_mode2speed(pata->mode);
1034         } else if (ccb->cts.transport == XPORT_SATA) {
1035                 struct  ccb_trans_settings_sata *sata =
1036                     &ccb->cts.xport_specific.sata;
1037
1038                 if (sata->valid & CTS_SATA_VALID_REVISION)
1039                         speed = ata_revision2speed(sata->revision);
1040         }
1041
1042         mb = speed / 1000;
1043         if (mb > 0) {
1044                 fprintf(stdout, "%s%d: %d.%03dMB/s transfers",
1045                         device->device_name, device->dev_unit_num,
1046                         mb, speed % 1000);
1047         } else {
1048                 fprintf(stdout, "%s%d: %dKB/s transfers",
1049                         device->device_name, device->dev_unit_num,
1050                         speed);
1051         }
1052
1053         if (ccb->cts.transport == XPORT_SPI) {
1054                 struct ccb_trans_settings_spi *spi =
1055                     &ccb->cts.xport_specific.spi;
1056
1057                 if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
1058                  && (spi->sync_offset != 0))
1059                         fprintf(stdout, " (%d.%03dMHz, offset %d", freq / 1000,
1060                                 freq % 1000, spi->sync_offset);
1061
1062                 if (((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0)
1063                  && (spi->bus_width > 0)) {
1064                         if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
1065                          && (spi->sync_offset != 0)) {
1066                                 fprintf(stdout, ", ");
1067                         } else {
1068                                 fprintf(stdout, " (");
1069                         }
1070                         fprintf(stdout, "%dbit)", 8 * (0x01 << spi->bus_width));
1071                 } else if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
1072                  && (spi->sync_offset != 0)) {
1073                         fprintf(stdout, ")");
1074                 }
1075         } else if (ccb->cts.transport == XPORT_ATA) {
1076                 struct ccb_trans_settings_pata *pata =
1077                     &ccb->cts.xport_specific.ata;
1078
1079                 printf(" (");
1080                 if (pata->valid & CTS_ATA_VALID_MODE)
1081                         printf("%s, ", ata_mode2string(pata->mode));
1082                 if ((pata->valid & CTS_ATA_VALID_ATAPI) && pata->atapi != 0)
1083                         printf("ATAPI %dbytes, ", pata->atapi);
1084                 if (pata->valid & CTS_ATA_VALID_BYTECOUNT)
1085                         printf("PIO %dbytes", pata->bytecount);
1086                 printf(")");
1087         } else if (ccb->cts.transport == XPORT_SATA) {
1088                 struct ccb_trans_settings_sata *sata =
1089                     &ccb->cts.xport_specific.sata;
1090
1091                 printf(" (");
1092                 if (sata->valid & CTS_SATA_VALID_REVISION)
1093                         printf("SATA %d.x, ", sata->revision);
1094                 else
1095                         printf("SATA, ");
1096                 if (sata->valid & CTS_SATA_VALID_MODE)
1097                         printf("%s, ", ata_mode2string(sata->mode));
1098                 if ((sata->valid & CTS_SATA_VALID_ATAPI) && sata->atapi != 0)
1099                         printf("ATAPI %dbytes, ", sata->atapi);
1100                 if (sata->valid & CTS_SATA_VALID_BYTECOUNT)
1101                         printf("PIO %dbytes", sata->bytecount);
1102                 printf(")");
1103         }
1104
1105         if (ccb->cts.protocol == PROTO_SCSI) {
1106                 struct ccb_trans_settings_scsi *scsi =
1107                     &ccb->cts.proto_specific.scsi;
1108                 if (scsi->valid & CTS_SCSI_VALID_TQ) {
1109                         if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) {
1110                                 fprintf(stdout, ", Command Queueing Enabled");
1111                         }
1112                 }
1113         }
1114
1115         fprintf(stdout, "\n");
1116
1117 xferrate_bailout:
1118
1119         cam_freeccb(ccb);
1120
1121         return(retval);
1122 }
1123
1124 static void
1125 atacapprint(struct ata_params *parm)
1126 {
1127         u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
1128                                 ((u_int32_t)parm->lba_size_2 << 16);
1129
1130         u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
1131                                 ((u_int64_t)parm->lba_size48_2 << 16) |
1132                                 ((u_int64_t)parm->lba_size48_3 << 32) |
1133                                 ((u_int64_t)parm->lba_size48_4 << 48);
1134
1135         printf("\n");
1136         printf("protocol              ");
1137         printf("ATA/ATAPI-%d", ata_version(parm->version_major));
1138         if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
1139                 if (parm->satacapabilities & ATA_SATA_GEN3)
1140                         printf(" SATA 3.x\n");
1141                 else if (parm->satacapabilities & ATA_SATA_GEN2)
1142                         printf(" SATA 2.x\n");
1143                 else if (parm->satacapabilities & ATA_SATA_GEN1)
1144                         printf(" SATA 1.x\n");
1145                 else
1146                         printf(" SATA\n");
1147         }
1148         else
1149                 printf("\n");
1150         printf("device model          %.40s\n", parm->model);
1151         printf("firmware revision     %.8s\n", parm->revision);
1152         printf("serial number         %.20s\n", parm->serial);
1153         if (parm->enabled.extension & ATA_SUPPORT_64BITWWN) {
1154                 printf("WWN                   %04x%04x%04x%04x\n",
1155                     parm->wwn[0], parm->wwn[1], parm->wwn[2], parm->wwn[3]);
1156         }
1157         if (parm->enabled.extension & ATA_SUPPORT_MEDIASN) {
1158                 printf("media serial number   %.30s\n",
1159                     parm->media_serial);
1160         }
1161
1162         printf("cylinders             %d\n", parm->cylinders);
1163         printf("heads                 %d\n", parm->heads);
1164         printf("sectors/track         %d\n", parm->sectors);
1165         printf("sector size           logical %u, physical %lu, offset %lu\n",
1166             ata_logical_sector_size(parm),
1167             (unsigned long)ata_physical_sector_size(parm),
1168             (unsigned long)ata_logical_sector_offset(parm));
1169
1170         if (parm->config == ATA_PROTO_CFA ||
1171             (parm->support.command2 & ATA_SUPPORT_CFA))
1172                 printf("CFA supported\n");
1173
1174         printf("LBA%ssupported         ",
1175                 parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not ");
1176         if (lbasize)
1177                 printf("%d sectors\n", lbasize);
1178         else
1179                 printf("\n");
1180
1181         printf("LBA48%ssupported       ",
1182                 parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not ");
1183         if (lbasize48)
1184                 printf("%ju sectors\n", (uintmax_t)lbasize48);
1185         else
1186                 printf("\n");
1187
1188         printf("PIO supported         PIO");
1189         switch (ata_max_pmode(parm)) {
1190         case ATA_PIO4:
1191                 printf("4");
1192                 break;
1193         case ATA_PIO3:
1194                 printf("3");
1195                 break;
1196         case ATA_PIO2:
1197                 printf("2");
1198                 break;
1199         case ATA_PIO1:
1200                 printf("1");
1201                 break;
1202         default:
1203                 printf("0");
1204         }
1205         if ((parm->capabilities1 & ATA_SUPPORT_IORDY) == 0)
1206                 printf(" w/o IORDY");
1207         printf("\n");
1208
1209         printf("DMA%ssupported         ",
1210                 parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not ");
1211         if (parm->capabilities1 & ATA_SUPPORT_DMA) {
1212                 if (parm->mwdmamodes & 0xff) {
1213                         printf("WDMA");
1214                         if (parm->mwdmamodes & 0x04)
1215                                 printf("2");
1216                         else if (parm->mwdmamodes & 0x02)
1217                                 printf("1");
1218                         else if (parm->mwdmamodes & 0x01)
1219                                 printf("0");
1220                         printf(" ");
1221                 }
1222                 if ((parm->atavalid & ATA_FLAG_88) &&
1223                     (parm->udmamodes & 0xff)) {
1224                         printf("UDMA");
1225                         if (parm->udmamodes & 0x40)
1226                                 printf("6");
1227                         else if (parm->udmamodes & 0x20)
1228                                 printf("5");
1229                         else if (parm->udmamodes & 0x10)
1230                                 printf("4");
1231                         else if (parm->udmamodes & 0x08)
1232                                 printf("3");
1233                         else if (parm->udmamodes & 0x04)
1234                                 printf("2");
1235                         else if (parm->udmamodes & 0x02)
1236                                 printf("1");
1237                         else if (parm->udmamodes & 0x01)
1238                                 printf("0");
1239                         printf(" ");
1240                 }
1241         }
1242         printf("\n");
1243
1244         if (parm->media_rotation_rate == 1) {
1245                 printf("media RPM             non-rotating\n");
1246         } else if (parm->media_rotation_rate >= 0x0401 &&
1247             parm->media_rotation_rate <= 0xFFFE) {
1248                 printf("media RPM             %d\n",
1249                         parm->media_rotation_rate);
1250         }
1251
1252         printf("\nFeature                      "
1253                 "Support  Enabled   Value           Vendor\n");
1254         printf("read ahead                     %s       %s\n",
1255                 parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no",
1256                 parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no");
1257         printf("write cache                    %s       %s\n",
1258                 parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no",
1259                 parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no");
1260         printf("flush cache                    %s       %s\n",
1261                 parm->support.command2 & ATA_SUPPORT_FLUSHCACHE ? "yes" : "no",
1262                 parm->enabled.command2 & ATA_SUPPORT_FLUSHCACHE ? "yes" : "no");
1263         printf("overlap                        %s\n",
1264                 parm->capabilities1 & ATA_SUPPORT_OVERLAP ? "yes" : "no");
1265         printf("Tagged Command Queuing (TCQ)   %s       %s",
1266                 parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
1267                 parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no");
1268                 if (parm->support.command2 & ATA_SUPPORT_QUEUED) {
1269                         printf("        %d tags\n",
1270                             ATA_QUEUE_LEN(parm->queue) + 1);
1271                 } else
1272                         printf("\n");
1273         printf("Native Command Queuing (NCQ)   ");
1274         if (parm->satacapabilities != 0xffff &&
1275             (parm->satacapabilities & ATA_SUPPORT_NCQ)) {
1276                 printf("yes             %d tags\n",
1277                     ATA_QUEUE_LEN(parm->queue) + 1);
1278         } else
1279                 printf("no\n");
1280         printf("SMART                          %s       %s\n",
1281                 parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no",
1282                 parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no");
1283         printf("microcode download             %s       %s\n",
1284                 parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no",
1285                 parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no");
1286         printf("security                       %s       %s\n",
1287                 parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no",
1288                 parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no");
1289         printf("power management               %s       %s\n",
1290                 parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no",
1291                 parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no");
1292         printf("advanced power management      %s       %s",
1293                 parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no",
1294                 parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no");
1295                 if (parm->support.command2 & ATA_SUPPORT_APM) {
1296                         printf("        %d/0x%02X\n",
1297                             parm->apm_value, parm->apm_value);
1298                 } else
1299                         printf("\n");
1300         printf("automatic acoustic management  %s       %s",
1301                 parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
1302                 parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no");
1303                 if (parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC) {
1304                         printf("        %d/0x%02X       %d/0x%02X\n",
1305                             ATA_ACOUSTIC_CURRENT(parm->acoustic),
1306                             ATA_ACOUSTIC_CURRENT(parm->acoustic),
1307                             ATA_ACOUSTIC_VENDOR(parm->acoustic),
1308                             ATA_ACOUSTIC_VENDOR(parm->acoustic));
1309                 } else
1310                         printf("\n");
1311         printf("media status notification      %s       %s\n",
1312                 parm->support.command2 & ATA_SUPPORT_NOTIFY ? "yes" : "no",
1313                 parm->enabled.command2 & ATA_SUPPORT_NOTIFY ? "yes" : "no");
1314         printf("power-up in Standby            %s       %s\n",
1315                 parm->support.command2 & ATA_SUPPORT_STANDBY ? "yes" : "no",
1316                 parm->enabled.command2 & ATA_SUPPORT_STANDBY ? "yes" : "no");
1317         printf("write-read-verify              %s       %s",
1318                 parm->support2 & ATA_SUPPORT_WRITEREADVERIFY ? "yes" : "no",
1319                 parm->enabled2 & ATA_SUPPORT_WRITEREADVERIFY ? "yes" : "no");
1320                 if (parm->support2 & ATA_SUPPORT_WRITEREADVERIFY) {
1321                         printf("        %d/0x%x\n",
1322                             parm->wrv_mode, parm->wrv_mode);
1323                 } else
1324                         printf("\n");
1325         printf("unload                         %s       %s\n",
1326                 parm->support.extension & ATA_SUPPORT_UNLOAD ? "yes" : "no",
1327                 parm->enabled.extension & ATA_SUPPORT_UNLOAD ? "yes" : "no");
1328         printf("free-fall                      %s       %s\n",
1329                 parm->support2 & ATA_SUPPORT_FREEFALL ? "yes" : "no",
1330                 parm->enabled2 & ATA_SUPPORT_FREEFALL ? "yes" : "no");
1331         printf("data set management (TRIM)     %s\n",
1332                 parm->support_dsm & ATA_SUPPORT_DSM_TRIM ? "yes" : "no");
1333 }
1334
1335 static int
1336 ataidentify(struct cam_device *device, int retry_count, int timeout)
1337 {
1338         union ccb *ccb;
1339         struct ata_params *ident_buf;
1340         struct ccb_getdev cgd;
1341         u_int i, error = 0;
1342         int16_t *ptr;
1343
1344         if (get_cgd(device, &cgd) != 0) {
1345                 warnx("couldn't get CGD");
1346                 return(1);
1347         }
1348         ccb = cam_getccb(device);
1349
1350         if (ccb == NULL) {
1351                 warnx("couldn't allocate CCB");
1352                 return(1);
1353         }
1354
1355         /* cam_getccb cleans up the header, caller has to zero the payload */
1356         bzero(&(&ccb->ccb_h)[1],
1357               sizeof(struct ccb_ataio) - sizeof(struct ccb_hdr));
1358
1359         ptr = (uint16_t *)malloc(sizeof(struct ata_params));
1360
1361         if (ptr == NULL) {
1362                 cam_freeccb(ccb);
1363                 warnx("can't malloc memory for identify\n");
1364                 return(1);
1365         }
1366         bzero(ptr, sizeof(struct ata_params));
1367
1368         cam_fill_ataio(&ccb->ataio,
1369                       retry_count,
1370                       NULL,
1371                       /*flags*/CAM_DIR_IN,
1372                       MSG_SIMPLE_Q_TAG,
1373                       /*data_ptr*/(u_int8_t *)ptr,
1374                       /*dxfer_len*/sizeof(struct ata_params),
1375                       timeout ? timeout : 30 * 1000);
1376         if (cgd.protocol == PROTO_ATA)
1377                 ata_28bit_cmd(&ccb->ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
1378         else
1379                 ata_28bit_cmd(&ccb->ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0);
1380
1381         /* Disable freezing the device queue */
1382         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
1383
1384         if (arglist & CAM_ARG_ERR_RECOVER)
1385                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
1386
1387         if (cam_send_ccb(device, ccb) < 0) {
1388                 perror("error sending ATA identify");
1389
1390                 if (arglist & CAM_ARG_VERBOSE) {
1391                         cam_error_print(device, ccb, CAM_ESF_ALL,
1392                                         CAM_EPF_ALL, stderr);
1393                 }
1394
1395                 free(ptr);
1396                 cam_freeccb(ccb);
1397                 return(1);
1398         }
1399
1400         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1401                 error = 1;
1402
1403                 if (arglist & CAM_ARG_VERBOSE) {
1404                         cam_error_print(device, ccb, CAM_ESF_ALL,
1405                                         CAM_EPF_ALL, stderr);
1406                 }
1407         }
1408
1409         cam_freeccb(ccb);
1410
1411         if (error != 0) {
1412                 free(ptr);
1413                 return(error);
1414         }
1415
1416         for (i = 0; i < sizeof(struct ata_params) / 2; i++)
1417                 ptr[i] = le16toh(ptr[i]);
1418         if (arglist & CAM_ARG_VERBOSE) {
1419                 fprintf(stdout, "%s%d: Raw identify data:\n",
1420                     device->device_name, device->dev_unit_num);
1421                 for (i = 0; i < sizeof(struct ata_params) / 2; i++) {
1422                         if ((i % 8) == 0)
1423                             fprintf(stdout, " %3d: ", i);
1424                         fprintf(stdout, "%04x ", (uint16_t)ptr[i]);
1425                         if ((i % 8) == 7)
1426                             fprintf(stdout, "\n");
1427                 }
1428         }
1429         ident_buf = (struct ata_params *)ptr;
1430         if (strncmp(ident_buf->model, "FX", 2) &&
1431             strncmp(ident_buf->model, "NEC", 3) &&
1432             strncmp(ident_buf->model, "Pioneer", 7) &&
1433             strncmp(ident_buf->model, "SHARP", 5)) {
1434                 ata_bswap(ident_buf->model, sizeof(ident_buf->model));
1435                 ata_bswap(ident_buf->revision, sizeof(ident_buf->revision));
1436                 ata_bswap(ident_buf->serial, sizeof(ident_buf->serial));
1437                 ata_bswap(ident_buf->media_serial, sizeof(ident_buf->media_serial));
1438         }
1439         ata_btrim(ident_buf->model, sizeof(ident_buf->model));
1440         ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model));
1441         ata_btrim(ident_buf->revision, sizeof(ident_buf->revision));
1442         ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision));
1443         ata_btrim(ident_buf->serial, sizeof(ident_buf->serial));
1444         ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial));
1445         ata_btrim(ident_buf->media_serial, sizeof(ident_buf->media_serial));
1446         ata_bpack(ident_buf->media_serial, ident_buf->media_serial,
1447             sizeof(ident_buf->media_serial));
1448
1449         fprintf(stdout, "%s%d: ", device->device_name,
1450                 device->dev_unit_num);
1451         ata_print_ident(ident_buf);
1452         camxferrate(device);
1453         atacapprint(ident_buf);
1454
1455         free(ident_buf);
1456
1457         return(0);
1458 }
1459 #endif /* MINIMALISTIC */
1460
1461 /*
1462  * Parse out a bus, or a bus, target and lun in the following
1463  * format:
1464  * bus
1465  * bus:target
1466  * bus:target:lun
1467  *
1468  * Returns the number of parsed components, or 0.
1469  */
1470 static int
1471 parse_btl(char *tstr, int *bus, int *target, int *lun, cam_argmask *arglst)
1472 {
1473         char *tmpstr;
1474         int convs = 0;
1475
1476         while (isspace(*tstr) && (*tstr != '\0'))
1477                 tstr++;
1478
1479         tmpstr = (char *)strtok(tstr, ":");
1480         if ((tmpstr != NULL) && (*tmpstr != '\0')) {
1481                 *bus = strtol(tmpstr, NULL, 0);
1482                 *arglst |= CAM_ARG_BUS;
1483                 convs++;
1484                 tmpstr = (char *)strtok(NULL, ":");
1485                 if ((tmpstr != NULL) && (*tmpstr != '\0')) {
1486                         *target = strtol(tmpstr, NULL, 0);
1487                         *arglst |= CAM_ARG_TARGET;
1488                         convs++;
1489                         tmpstr = (char *)strtok(NULL, ":");
1490                         if ((tmpstr != NULL) && (*tmpstr != '\0')) {
1491                                 *lun = strtol(tmpstr, NULL, 0);
1492                                 *arglst |= CAM_ARG_LUN;
1493                                 convs++;
1494                         }
1495                 }
1496         }
1497
1498         return convs;
1499 }
1500
1501 static int
1502 dorescan_or_reset(int argc, char **argv, int rescan)
1503 {
1504         static const char must[] =
1505                 "you must specify \"all\", a bus, or a bus:target:lun to %s";
1506         int rv, error = 0;
1507         int bus = -1, target = -1, lun = -1;
1508         char *tstr;
1509
1510         if (argc < 3) {
1511                 warnx(must, rescan? "rescan" : "reset");
1512                 return(1);
1513         }
1514
1515         tstr = argv[optind];
1516         while (isspace(*tstr) && (*tstr != '\0'))
1517                 tstr++;
1518         if (strncasecmp(tstr, "all", strlen("all")) == 0)
1519                 arglist |= CAM_ARG_BUS;
1520         else {
1521                 rv = parse_btl(argv[optind], &bus, &target, &lun, &arglist);
1522                 if (rv != 1 && rv != 3) {
1523                         warnx(must, rescan? "rescan" : "reset");
1524                         return(1);
1525                 }
1526         }
1527
1528         if ((arglist & CAM_ARG_BUS)
1529             && (arglist & CAM_ARG_TARGET)
1530             && (arglist & CAM_ARG_LUN))
1531                 error = scanlun_or_reset_dev(bus, target, lun, rescan);
1532         else
1533                 error = rescan_or_reset_bus(bus, rescan);
1534
1535         return(error);
1536 }
1537
1538 static int
1539 rescan_or_reset_bus(int bus, int rescan)
1540 {
1541         union ccb ccb, matchccb;
1542         int fd, retval;
1543         int bufsize;
1544
1545         retval = 0;
1546
1547         if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
1548                 warnx("error opening transport layer device %s", XPT_DEVICE);
1549                 warn("%s", XPT_DEVICE);
1550                 return(1);
1551         }
1552
1553         if (bus != -1) {
1554                 ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS : XPT_RESET_BUS;
1555                 ccb.ccb_h.path_id = bus;
1556                 ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
1557                 ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
1558                 ccb.crcn.flags = CAM_FLAG_NONE;
1559
1560                 /* run this at a low priority */
1561                 ccb.ccb_h.pinfo.priority = 5;
1562
1563                 if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
1564                         warn("CAMIOCOMMAND ioctl failed");
1565                         close(fd);
1566                         return(1);
1567                 }
1568
1569                 if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
1570                         fprintf(stdout, "%s of bus %d was successful\n",
1571                             rescan ? "Re-scan" : "Reset", bus);
1572                 } else {
1573                         fprintf(stdout, "%s of bus %d returned error %#x\n",
1574                                 rescan ? "Re-scan" : "Reset", bus,
1575                                 ccb.ccb_h.status & CAM_STATUS_MASK);
1576                         retval = 1;
1577                 }
1578
1579                 close(fd);
1580                 return(retval);
1581
1582         }
1583
1584
1585         /*
1586          * The right way to handle this is to modify the xpt so that it can
1587          * handle a wildcarded bus in a rescan or reset CCB.  At the moment
1588          * that isn't implemented, so instead we enumerate the busses and
1589          * send the rescan or reset to those busses in the case where the
1590          * given bus is -1 (wildcard).  We don't send a rescan or reset
1591          * to the xpt bus; sending a rescan to the xpt bus is effectively a
1592          * no-op, sending a rescan to the xpt bus would result in a status of
1593          * CAM_REQ_INVALID.
1594          */
1595         bzero(&(&matchccb.ccb_h)[1],
1596               sizeof(struct ccb_dev_match) - sizeof(struct ccb_hdr));
1597         matchccb.ccb_h.func_code = XPT_DEV_MATCH;
1598         matchccb.ccb_h.path_id = CAM_BUS_WILDCARD;
1599         bufsize = sizeof(struct dev_match_result) * 20;
1600         matchccb.cdm.match_buf_len = bufsize;
1601         matchccb.cdm.matches=(struct dev_match_result *)malloc(bufsize);
1602         if (matchccb.cdm.matches == NULL) {
1603                 warnx("can't malloc memory for matches");
1604                 retval = 1;
1605                 goto bailout;
1606         }
1607         matchccb.cdm.num_matches = 0;
1608
1609         matchccb.cdm.num_patterns = 1;
1610         matchccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern);
1611
1612         matchccb.cdm.patterns = (struct dev_match_pattern *)malloc(
1613                 matchccb.cdm.pattern_buf_len);
1614         if (matchccb.cdm.patterns == NULL) {
1615                 warnx("can't malloc memory for patterns");
1616                 retval = 1;
1617                 goto bailout;
1618         }
1619         matchccb.cdm.patterns[0].type = DEV_MATCH_BUS;
1620         matchccb.cdm.patterns[0].pattern.bus_pattern.flags = BUS_MATCH_ANY;
1621
1622         do {
1623                 unsigned int i;
1624
1625                 if (ioctl(fd, CAMIOCOMMAND, &matchccb) == -1) {
1626                         warn("CAMIOCOMMAND ioctl failed");
1627                         retval = 1;
1628                         goto bailout;
1629                 }
1630
1631                 if ((matchccb.ccb_h.status != CAM_REQ_CMP)
1632                  || ((matchccb.cdm.status != CAM_DEV_MATCH_LAST)
1633                    && (matchccb.cdm.status != CAM_DEV_MATCH_MORE))) {
1634                         warnx("got CAM error %#x, CDM error %d\n",
1635                               matchccb.ccb_h.status, matchccb.cdm.status);
1636                         retval = 1;
1637                         goto bailout;
1638                 }
1639
1640                 for (i = 0; i < matchccb.cdm.num_matches; i++) {
1641                         struct bus_match_result *bus_result;
1642
1643                         /* This shouldn't happen. */
1644                         if (matchccb.cdm.matches[i].type != DEV_MATCH_BUS)
1645                                 continue;
1646
1647                         bus_result = &matchccb.cdm.matches[i].result.bus_result;
1648
1649                         /*
1650                          * We don't want to rescan or reset the xpt bus.
1651                          * See above.
1652                          */
1653                         if ((int)bus_result->path_id == -1)
1654                                 continue;
1655
1656                         ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS :
1657                                                        XPT_RESET_BUS;
1658                         ccb.ccb_h.path_id = bus_result->path_id;
1659                         ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
1660                         ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
1661                         ccb.crcn.flags = CAM_FLAG_NONE;
1662
1663                         /* run this at a low priority */
1664                         ccb.ccb_h.pinfo.priority = 5;
1665
1666                         if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
1667                                 warn("CAMIOCOMMAND ioctl failed");
1668                                 retval = 1;
1669                                 goto bailout;
1670                         }
1671
1672                         if ((ccb.ccb_h.status & CAM_STATUS_MASK) ==CAM_REQ_CMP){
1673                                 fprintf(stdout, "%s of bus %d was successful\n",
1674                                         rescan? "Re-scan" : "Reset",
1675                                         bus_result->path_id);
1676                         } else {
1677                                 /*
1678                                  * Don't bail out just yet, maybe the other
1679                                  * rescan or reset commands will complete
1680                                  * successfully.
1681                                  */
1682                                 fprintf(stderr, "%s of bus %d returned error "
1683                                         "%#x\n", rescan? "Re-scan" : "Reset",
1684                                         bus_result->path_id,
1685                                         ccb.ccb_h.status & CAM_STATUS_MASK);
1686                                 retval = 1;
1687                         }
1688                 }
1689         } while ((matchccb.ccb_h.status == CAM_REQ_CMP)
1690                  && (matchccb.cdm.status == CAM_DEV_MATCH_MORE));
1691
1692 bailout:
1693
1694         if (fd != -1)
1695                 close(fd);
1696
1697         if (matchccb.cdm.patterns != NULL)
1698                 free(matchccb.cdm.patterns);
1699         if (matchccb.cdm.matches != NULL)
1700                 free(matchccb.cdm.matches);
1701
1702         return(retval);
1703 }
1704
1705 static int
1706 scanlun_or_reset_dev(int bus, int target, int lun, int scan)
1707 {
1708         union ccb ccb;
1709         struct cam_device *device;
1710         int fd;
1711
1712         device = NULL;
1713
1714         if (bus < 0) {
1715                 warnx("invalid bus number %d", bus);
1716                 return(1);
1717         }
1718
1719         if (target < 0) {
1720                 warnx("invalid target number %d", target);
1721                 return(1);
1722         }
1723
1724         if (lun < 0) {
1725                 warnx("invalid lun number %d", lun);
1726                 return(1);
1727         }
1728
1729         fd = -1;
1730
1731         bzero(&ccb, sizeof(union ccb));
1732
1733         if (scan) {
1734                 if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
1735                         warnx("error opening transport layer device %s\n",
1736                             XPT_DEVICE);
1737                         warn("%s", XPT_DEVICE);
1738                         return(1);
1739                 }
1740         } else {
1741                 device = cam_open_btl(bus, target, lun, O_RDWR, NULL);
1742                 if (device == NULL) {
1743                         warnx("%s", cam_errbuf);
1744                         return(1);
1745                 }
1746         }
1747
1748         ccb.ccb_h.func_code = (scan)? XPT_SCAN_LUN : XPT_RESET_DEV;
1749         ccb.ccb_h.path_id = bus;
1750         ccb.ccb_h.target_id = target;
1751         ccb.ccb_h.target_lun = lun;
1752         ccb.ccb_h.timeout = 5000;
1753         ccb.crcn.flags = CAM_FLAG_NONE;
1754
1755         /* run this at a low priority */
1756         ccb.ccb_h.pinfo.priority = 5;
1757
1758         if (scan) {
1759                 if (ioctl(fd, CAMIOCOMMAND, &ccb) < 0) {
1760                         warn("CAMIOCOMMAND ioctl failed");
1761                         close(fd);
1762                         return(1);
1763                 }
1764         } else {
1765                 if (cam_send_ccb(device, &ccb) < 0) {
1766                         warn("error sending XPT_RESET_DEV CCB");
1767                         cam_close_device(device);
1768                         return(1);
1769                 }
1770         }
1771
1772         if (scan)
1773                 close(fd);
1774         else
1775                 cam_close_device(device);
1776
1777         /*
1778          * An error code of CAM_BDR_SENT is normal for a BDR request.
1779          */
1780         if (((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
1781          || ((!scan)
1782           && ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_BDR_SENT))) {
1783                 fprintf(stdout, "%s of %d:%d:%d was successful\n",
1784                     scan? "Re-scan" : "Reset", bus, target, lun);
1785                 return(0);
1786         } else {
1787                 fprintf(stdout, "%s of %d:%d:%d returned error %#x\n",
1788                     scan? "Re-scan" : "Reset", bus, target, lun,
1789                     ccb.ccb_h.status & CAM_STATUS_MASK);
1790                 return(1);
1791         }
1792 }
1793
1794 #ifndef MINIMALISTIC
1795 static int
1796 readdefects(struct cam_device *device, int argc, char **argv,
1797             char *combinedopt, int retry_count, int timeout)
1798 {
1799         union ccb *ccb = NULL;
1800         struct scsi_read_defect_data_10 *rdd_cdb;
1801         u_int8_t *defect_list = NULL;
1802         u_int32_t dlist_length = 65000;
1803         u_int32_t returned_length = 0;
1804         u_int32_t num_returned = 0;
1805         u_int8_t returned_format;
1806         unsigned int i;
1807         int c, error = 0;
1808         int lists_specified = 0;
1809
1810         while ((c = getopt(argc, argv, combinedopt)) != -1) {
1811                 switch(c){
1812                 case 'f':
1813                 {
1814                         char *tstr;
1815                         tstr = optarg;
1816                         while (isspace(*tstr) && (*tstr != '\0'))
1817                                 tstr++;
1818                         if (strcmp(tstr, "block") == 0)
1819                                 arglist |= CAM_ARG_FORMAT_BLOCK;
1820                         else if (strcmp(tstr, "bfi") == 0)
1821                                 arglist |= CAM_ARG_FORMAT_BFI;
1822                         else if (strcmp(tstr, "phys") == 0)
1823                                 arglist |= CAM_ARG_FORMAT_PHYS;
1824                         else {
1825                                 error = 1;
1826                                 warnx("invalid defect format %s", tstr);
1827                                 goto defect_bailout;
1828                         }
1829                         break;
1830                 }
1831                 case 'G':
1832                         arglist |= CAM_ARG_GLIST;
1833                         break;
1834                 case 'P':
1835                         arglist |= CAM_ARG_PLIST;
1836                         break;
1837                 default:
1838                         break;
1839                 }
1840         }
1841
1842         ccb = cam_getccb(device);
1843
1844         /*
1845          * Hopefully 65000 bytes is enough to hold the defect list.  If it
1846          * isn't, the disk is probably dead already.  We'd have to go with
1847          * 12 byte command (i.e. alloc_length is 32 bits instead of 16)
1848          * to hold them all.
1849          */
1850         defect_list = malloc(dlist_length);
1851         if (defect_list == NULL) {
1852                 warnx("can't malloc memory for defect list");
1853                 error = 1;
1854                 goto defect_bailout;
1855         }
1856
1857         rdd_cdb =(struct scsi_read_defect_data_10 *)&ccb->csio.cdb_io.cdb_bytes;
1858
1859         /*
1860          * cam_getccb() zeros the CCB header only.  So we need to zero the
1861          * payload portion of the ccb.
1862          */
1863         bzero(&(&ccb->ccb_h)[1],
1864               sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
1865
1866         cam_fill_csio(&ccb->csio,
1867                       /*retries*/ retry_count,
1868                       /*cbfcnp*/ NULL,
1869                       /*flags*/ CAM_DIR_IN | ((arglist & CAM_ARG_ERR_RECOVER) ?
1870                                               CAM_PASS_ERR_RECOVER : 0),
1871                       /*tag_action*/ MSG_SIMPLE_Q_TAG,
1872                       /*data_ptr*/ defect_list,
1873                       /*dxfer_len*/ dlist_length,
1874                       /*sense_len*/ SSD_FULL_SIZE,
1875                       /*cdb_len*/ sizeof(struct scsi_read_defect_data_10),
1876                       /*timeout*/ timeout ? timeout : 5000);
1877
1878         rdd_cdb->opcode = READ_DEFECT_DATA_10;
1879         if (arglist & CAM_ARG_FORMAT_BLOCK)
1880                 rdd_cdb->format = SRDD10_BLOCK_FORMAT;
1881         else if (arglist & CAM_ARG_FORMAT_BFI)
1882                 rdd_cdb->format = SRDD10_BYTES_FROM_INDEX_FORMAT;
1883         else if (arglist & CAM_ARG_FORMAT_PHYS)
1884                 rdd_cdb->format = SRDD10_PHYSICAL_SECTOR_FORMAT;
1885         else {
1886                 error = 1;
1887                 warnx("no defect list format specified");
1888                 goto defect_bailout;
1889         }
1890         if (arglist & CAM_ARG_PLIST) {
1891                 rdd_cdb->format |= SRDD10_PLIST;
1892                 lists_specified++;
1893         }
1894
1895         if (arglist & CAM_ARG_GLIST) {
1896                 rdd_cdb->format |= SRDD10_GLIST;
1897                 lists_specified++;
1898         }
1899
1900         scsi_ulto2b(dlist_length, rdd_cdb->alloc_length);
1901
1902         /* Disable freezing the device queue */
1903         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
1904
1905         if (cam_send_ccb(device, ccb) < 0) {
1906                 perror("error reading defect list");
1907
1908                 if (arglist & CAM_ARG_VERBOSE) {
1909                         cam_error_print(device, ccb, CAM_ESF_ALL,
1910                                         CAM_EPF_ALL, stderr);
1911                 }
1912
1913                 error = 1;
1914                 goto defect_bailout;
1915         }
1916
1917         returned_length = scsi_2btoul(((struct
1918                 scsi_read_defect_data_hdr_10 *)defect_list)->length);
1919
1920         returned_format = ((struct scsi_read_defect_data_hdr_10 *)
1921                         defect_list)->format;
1922
1923         if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR)
1924          && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
1925          && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) {
1926                 struct scsi_sense_data *sense;
1927                 int error_code, sense_key, asc, ascq;
1928
1929                 sense = &ccb->csio.sense_data;
1930                 scsi_extract_sense_len(sense, ccb->csio.sense_len -
1931                     ccb->csio.sense_resid, &error_code, &sense_key, &asc,
1932                     &ascq, /*show_errors*/ 1);
1933
1934                 /*
1935                  * According to the SCSI spec, if the disk doesn't support
1936                  * the requested format, it will generally return a sense
1937                  * key of RECOVERED ERROR, and an additional sense code
1938                  * of "DEFECT LIST NOT FOUND".  So, we check for that, and
1939                  * also check to make sure that the returned length is
1940                  * greater than 0, and then print out whatever format the
1941                  * disk gave us.
1942                  */
1943                 if ((sense_key == SSD_KEY_RECOVERED_ERROR)
1944                  && (asc == 0x1c) && (ascq == 0x00)
1945                  && (returned_length > 0)) {
1946                         warnx("requested defect format not available");
1947                         switch(returned_format & SRDDH10_DLIST_FORMAT_MASK) {
1948                         case SRDD10_BLOCK_FORMAT:
1949                                 warnx("Device returned block format");
1950                                 break;
1951                         case SRDD10_BYTES_FROM_INDEX_FORMAT:
1952                                 warnx("Device returned bytes from index"
1953                                       " format");
1954                                 break;
1955                         case SRDD10_PHYSICAL_SECTOR_FORMAT:
1956                                 warnx("Device returned physical sector format");
1957                                 break;
1958                         default:
1959                                 error = 1;
1960                                 warnx("Device returned unknown defect"
1961                                      " data format %#x", returned_format);
1962                                 goto defect_bailout;
1963                                 break; /* NOTREACHED */
1964                         }
1965                 } else {
1966                         error = 1;
1967                         warnx("Error returned from read defect data command");
1968                         if (arglist & CAM_ARG_VERBOSE)
1969                                 cam_error_print(device, ccb, CAM_ESF_ALL,
1970                                                 CAM_EPF_ALL, stderr);
1971                         goto defect_bailout;
1972                 }
1973         } else if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1974                 error = 1;
1975                 warnx("Error returned from read defect data command");
1976                 if (arglist & CAM_ARG_VERBOSE)
1977                         cam_error_print(device, ccb, CAM_ESF_ALL,
1978                                         CAM_EPF_ALL, stderr);
1979                 goto defect_bailout;
1980         }
1981
1982         /*
1983          * XXX KDM  I should probably clean up the printout format for the
1984          * disk defects.
1985          */
1986         switch (returned_format & SRDDH10_DLIST_FORMAT_MASK){
1987                 case SRDDH10_PHYSICAL_SECTOR_FORMAT:
1988                 {
1989                         struct scsi_defect_desc_phys_sector *dlist;
1990
1991                         dlist = (struct scsi_defect_desc_phys_sector *)
1992                                 (defect_list +
1993                                 sizeof(struct scsi_read_defect_data_hdr_10));
1994
1995                         num_returned = returned_length /
1996                                 sizeof(struct scsi_defect_desc_phys_sector);
1997
1998                         fprintf(stderr, "Got %d defect", num_returned);
1999
2000                         if ((lists_specified == 0) || (num_returned == 0)) {
2001                                 fprintf(stderr, "s.\n");
2002                                 break;
2003                         } else if (num_returned == 1)
2004                                 fprintf(stderr, ":\n");
2005                         else
2006                                 fprintf(stderr, "s:\n");
2007
2008                         for (i = 0; i < num_returned; i++) {
2009                                 fprintf(stdout, "%d:%d:%d\n",
2010                                         scsi_3btoul(dlist[i].cylinder),
2011                                         dlist[i].head,
2012                                         scsi_4btoul(dlist[i].sector));
2013                         }
2014                         break;
2015                 }
2016                 case SRDDH10_BYTES_FROM_INDEX_FORMAT:
2017                 {
2018                         struct scsi_defect_desc_bytes_from_index *dlist;
2019
2020                         dlist = (struct scsi_defect_desc_bytes_from_index *)
2021                                 (defect_list +
2022                                 sizeof(struct scsi_read_defect_data_hdr_10));
2023
2024                         num_returned = returned_length /
2025                               sizeof(struct scsi_defect_desc_bytes_from_index);
2026
2027                         fprintf(stderr, "Got %d defect", num_returned);
2028
2029                         if ((lists_specified == 0) || (num_returned == 0)) {
2030                                 fprintf(stderr, "s.\n");
2031                                 break;
2032                         } else if (num_returned == 1)
2033                                 fprintf(stderr, ":\n");
2034                         else
2035                                 fprintf(stderr, "s:\n");
2036
2037                         for (i = 0; i < num_returned; i++) {
2038                                 fprintf(stdout, "%d:%d:%d\n",
2039                                         scsi_3btoul(dlist[i].cylinder),
2040                                         dlist[i].head,
2041                                         scsi_4btoul(dlist[i].bytes_from_index));
2042                         }
2043                         break;
2044                 }
2045                 case SRDDH10_BLOCK_FORMAT:
2046                 {
2047                         struct scsi_defect_desc_block *dlist;
2048
2049                         dlist = (struct scsi_defect_desc_block *)(defect_list +
2050                                 sizeof(struct scsi_read_defect_data_hdr_10));
2051
2052                         num_returned = returned_length /
2053                               sizeof(struct scsi_defect_desc_block);
2054
2055                         fprintf(stderr, "Got %d defect", num_returned);
2056
2057                         if ((lists_specified == 0) || (num_returned == 0)) {
2058                                 fprintf(stderr, "s.\n");
2059                                 break;
2060                         } else if (num_returned == 1)
2061                                 fprintf(stderr, ":\n");
2062                         else
2063                                 fprintf(stderr, "s:\n");
2064
2065                         for (i = 0; i < num_returned; i++)
2066                                 fprintf(stdout, "%u\n",
2067                                         scsi_4btoul(dlist[i].address));
2068                         break;
2069                 }
2070                 default:
2071                         fprintf(stderr, "Unknown defect format %d\n",
2072                                 returned_format & SRDDH10_DLIST_FORMAT_MASK);
2073                         error = 1;
2074                         break;
2075         }
2076 defect_bailout:
2077
2078         if (defect_list != NULL)
2079                 free(defect_list);
2080
2081         if (ccb != NULL)
2082                 cam_freeccb(ccb);
2083
2084         return(error);
2085 }
2086 #endif /* MINIMALISTIC */
2087
2088 #if 0
2089 void
2090 reassignblocks(struct cam_device *device, u_int32_t *blocks, int num_blocks)
2091 {
2092         union ccb *ccb;
2093
2094         ccb = cam_getccb(device);
2095
2096         cam_freeccb(ccb);
2097 }
2098 #endif
2099
2100 #ifndef MINIMALISTIC
2101 void
2102 mode_sense(struct cam_device *device, int mode_page, int page_control,
2103            int dbd, int retry_count, int timeout, u_int8_t *data, int datalen)
2104 {
2105         union ccb *ccb;
2106         int retval;
2107
2108         ccb = cam_getccb(device);
2109
2110         if (ccb == NULL)
2111                 errx(1, "mode_sense: couldn't allocate CCB");
2112
2113         bzero(&(&ccb->ccb_h)[1],
2114               sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
2115
2116         scsi_mode_sense(&ccb->csio,
2117                         /* retries */ retry_count,
2118                         /* cbfcnp */ NULL,
2119                         /* tag_action */ MSG_SIMPLE_Q_TAG,
2120                         /* dbd */ dbd,
2121                         /* page_code */ page_control << 6,
2122                         /* page */ mode_page,
2123                         /* param_buf */ data,
2124                         /* param_len */ datalen,
2125                         /* sense_len */ SSD_FULL_SIZE,
2126                         /* timeout */ timeout ? timeout : 5000);
2127
2128         if (arglist & CAM_ARG_ERR_RECOVER)
2129                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
2130
2131         /* Disable freezing the device queue */
2132         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
2133
2134         if (((retval = cam_send_ccb(device, ccb)) < 0)
2135          || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
2136                 if (arglist & CAM_ARG_VERBOSE) {
2137                         cam_error_print(device, ccb, CAM_ESF_ALL,
2138                                         CAM_EPF_ALL, stderr);
2139                 }
2140                 cam_freeccb(ccb);
2141                 cam_close_device(device);
2142                 if (retval < 0)
2143                         err(1, "error sending mode sense command");
2144                 else
2145                         errx(1, "error sending mode sense command");
2146         }
2147
2148         cam_freeccb(ccb);
2149 }
2150
2151 void
2152 mode_select(struct cam_device *device, int save_pages, int retry_count,
2153            int timeout, u_int8_t *data, int datalen)
2154 {
2155         union ccb *ccb;
2156         int retval;
2157
2158         ccb = cam_getccb(device);
2159
2160         if (ccb == NULL)
2161                 errx(1, "mode_select: couldn't allocate CCB");
2162
2163         bzero(&(&ccb->ccb_h)[1],
2164               sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
2165
2166         scsi_mode_select(&ccb->csio,
2167                          /* retries */ retry_count,
2168                          /* cbfcnp */ NULL,
2169                          /* tag_action */ MSG_SIMPLE_Q_TAG,
2170                          /* scsi_page_fmt */ 1,
2171                          /* save_pages */ save_pages,
2172                          /* param_buf */ data,
2173                          /* param_len */ datalen,
2174                          /* sense_len */ SSD_FULL_SIZE,
2175                          /* timeout */ timeout ? timeout : 5000);
2176
2177         if (arglist & CAM_ARG_ERR_RECOVER)
2178                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
2179
2180         /* Disable freezing the device queue */
2181         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
2182
2183         if (((retval = cam_send_ccb(device, ccb)) < 0)
2184          || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
2185                 if (arglist & CAM_ARG_VERBOSE) {
2186                         cam_error_print(device, ccb, CAM_ESF_ALL,
2187                                         CAM_EPF_ALL, stderr);
2188                 }
2189                 cam_freeccb(ccb);
2190                 cam_close_device(device);
2191
2192                 if (retval < 0)
2193                         err(1, "error sending mode select command");
2194                 else
2195                         errx(1, "error sending mode select command");
2196
2197         }
2198
2199         cam_freeccb(ccb);
2200 }
2201
2202 void
2203 modepage(struct cam_device *device, int argc, char **argv, char *combinedopt,
2204          int retry_count, int timeout)
2205 {
2206         int c, mode_page = -1, page_control = 0;
2207         int binary = 0, list = 0;
2208
2209         while ((c = getopt(argc, argv, combinedopt)) != -1) {
2210                 switch(c) {
2211                 case 'b':
2212                         binary = 1;
2213                         break;
2214                 case 'd':
2215                         arglist |= CAM_ARG_DBD;
2216                         break;
2217                 case 'e':
2218                         arglist |= CAM_ARG_MODE_EDIT;
2219                         break;
2220                 case 'l':
2221                         list = 1;
2222                         break;
2223                 case 'm':
2224                         mode_page = strtol(optarg, NULL, 0);
2225                         if (mode_page < 0)
2226                                 errx(1, "invalid mode page %d", mode_page);
2227                         break;
2228                 case 'P':
2229                         page_control = strtol(optarg, NULL, 0);
2230                         if ((page_control < 0) || (page_control > 3))
2231                                 errx(1, "invalid page control field %d",
2232                                      page_control);
2233                         arglist |= CAM_ARG_PAGE_CNTL;
2234                         break;
2235                 default:
2236                         break;
2237                 }
2238         }
2239
2240         if (mode_page == -1 && list == 0)
2241                 errx(1, "you must specify a mode page!");
2242
2243         if (list) {
2244                 mode_list(device, page_control, arglist & CAM_ARG_DBD,
2245                     retry_count, timeout);
2246         } else {
2247                 mode_edit(device, mode_page, page_control,
2248                     arglist & CAM_ARG_DBD, arglist & CAM_ARG_MODE_EDIT, binary,
2249                     retry_count, timeout);
2250         }
2251 }
2252
2253 static int
2254 scsicmd(struct cam_device *device, int argc, char **argv, char *combinedopt,
2255         int retry_count, int timeout)
2256 {
2257         union ccb *ccb;
2258         u_int32_t flags = CAM_DIR_NONE;
2259         u_int8_t *data_ptr = NULL;
2260         u_int8_t cdb[20];
2261         u_int8_t atacmd[12];
2262         struct get_hook hook;
2263         int c, data_bytes = 0;
2264         int cdb_len = 0;
2265         int atacmd_len = 0;
2266         int dmacmd = 0;
2267         int fpdmacmd = 0;
2268         int need_res = 0;
2269         char *datastr = NULL, *tstr, *resstr = NULL;
2270         int error = 0;
2271         int fd_data = 0, fd_res = 0;
2272         int retval;
2273
2274         ccb = cam_getccb(device);
2275
2276         if (ccb == NULL) {
2277                 warnx("scsicmd: error allocating ccb");
2278                 return(1);
2279         }
2280
2281         bzero(&(&ccb->ccb_h)[1],
2282               sizeof(union ccb) - sizeof(struct ccb_hdr));
2283
2284         while ((c = getopt(argc, argv, combinedopt)) != -1) {
2285                 switch(c) {
2286                 case 'a':
2287                         tstr = optarg;
2288                         while (isspace(*tstr) && (*tstr != '\0'))
2289                                 tstr++;
2290                         hook.argc = argc - optind;
2291                         hook.argv = argv + optind;
2292                         hook.got = 0;
2293                         atacmd_len = buff_encode_visit(atacmd, sizeof(atacmd), tstr,
2294                                                     iget, &hook);
2295                         /*
2296                          * Increment optind by the number of arguments the
2297                          * encoding routine processed.  After each call to
2298                          * getopt(3), optind points to the argument that
2299                          * getopt should process _next_.  In this case,
2300                          * that means it points to the first command string
2301                          * argument, if there is one.  Once we increment
2302                          * this, it should point to either the next command
2303                          * line argument, or it should be past the end of
2304                          * the list.
2305                          */
2306                         optind += hook.got;
2307                         break;
2308                 case 'c':
2309                         tstr = optarg;
2310                         while (isspace(*tstr) && (*tstr != '\0'))
2311                                 tstr++;
2312                         hook.argc = argc - optind;
2313                         hook.argv = argv + optind;
2314                         hook.got = 0;
2315                         cdb_len = buff_encode_visit(cdb, sizeof(cdb), tstr,
2316                                                     iget, &hook);
2317                         /*
2318                          * Increment optind by the number of arguments the
2319                          * encoding routine processed.  After each call to
2320                          * getopt(3), optind points to the argument that
2321                          * getopt should process _next_.  In this case,
2322                          * that means it points to the first command string
2323                          * argument, if there is one.  Once we increment
2324                          * this, it should point to either the next command
2325                          * line argument, or it should be past the end of
2326                          * the list.
2327                          */
2328                         optind += hook.got;
2329                         break;
2330                 case 'd':
2331                         dmacmd = 1;
2332                         break;
2333                 case 'f':
2334                         fpdmacmd = 1;
2335                         break;
2336                 case 'i':
2337                         if (arglist & CAM_ARG_CMD_OUT) {
2338                                 warnx("command must either be "
2339                                       "read or write, not both");
2340                                 error = 1;
2341                                 goto scsicmd_bailout;
2342                         }
2343                         arglist |= CAM_ARG_CMD_IN;
2344                         flags = CAM_DIR_IN;
2345                         data_bytes = strtol(optarg, NULL, 0);
2346                         if (data_bytes <= 0) {
2347                                 warnx("invalid number of input bytes %d",
2348                                       data_bytes);
2349                                 error = 1;
2350                                 goto scsicmd_bailout;
2351                         }
2352                         hook.argc = argc - optind;
2353                         hook.argv = argv + optind;
2354                         hook.got = 0;
2355                         optind++;
2356                         datastr = cget(&hook, NULL);
2357                         /*
2358                          * If the user supplied "-" instead of a format, he
2359                          * wants the data to be written to stdout.
2360                          */
2361                         if ((datastr != NULL)
2362                          && (datastr[0] == '-'))
2363                                 fd_data = 1;
2364
2365                         data_ptr = (u_int8_t *)malloc(data_bytes);
2366                         if (data_ptr == NULL) {
2367                                 warnx("can't malloc memory for data_ptr");
2368                                 error = 1;
2369                                 goto scsicmd_bailout;
2370                         }
2371                         break;
2372                 case 'o':
2373                         if (arglist & CAM_ARG_CMD_IN) {
2374                                 warnx("command must either be "
2375                                       "read or write, not both");
2376                                 error = 1;
2377                                 goto scsicmd_bailout;
2378                         }
2379                         arglist |= CAM_ARG_CMD_OUT;
2380                         flags = CAM_DIR_OUT;
2381                         data_bytes = strtol(optarg, NULL, 0);
2382                         if (data_bytes <= 0) {
2383                                 warnx("invalid number of output bytes %d",
2384                                       data_bytes);
2385                                 error = 1;
2386                                 goto scsicmd_bailout;
2387                         }
2388                         hook.argc = argc - optind;
2389                         hook.argv = argv + optind;
2390                         hook.got = 0;
2391                         datastr = cget(&hook, NULL);
2392                         data_ptr = (u_int8_t *)malloc(data_bytes);
2393                         if (data_ptr == NULL) {
2394                                 warnx("can't malloc memory for data_ptr");
2395                                 error = 1;
2396                                 goto scsicmd_bailout;
2397                         }
2398                         bzero(data_ptr, data_bytes);
2399                         /*
2400                          * If the user supplied "-" instead of a format, he
2401                          * wants the data to be read from stdin.
2402                          */
2403                         if ((datastr != NULL)
2404                          && (datastr[0] == '-'))
2405                                 fd_data = 1;
2406                         else
2407                                 buff_encode_visit(data_ptr, data_bytes, datastr,
2408                                                   iget, &hook);
2409                         optind += hook.got;
2410                         break;
2411                 case 'r':
2412                         need_res = 1;
2413                         hook.argc = argc - optind;
2414                         hook.argv = argv + optind;
2415                         hook.got = 0;
2416                         resstr = cget(&hook, NULL);
2417                         if ((resstr != NULL) && (resstr[0] == '-'))
2418                                 fd_res = 1;
2419                         optind += hook.got;
2420                         break;
2421                 default:
2422                         break;
2423                 }
2424         }
2425
2426         /*
2427          * If fd_data is set, and we're writing to the device, we need to
2428          * read the data the user wants written from stdin.
2429          */
2430         if ((fd_data == 1) && (arglist & CAM_ARG_CMD_OUT)) {
2431                 ssize_t amt_read;
2432                 int amt_to_read = data_bytes;
2433                 u_int8_t *buf_ptr = data_ptr;
2434
2435                 for (amt_read = 0; amt_to_read > 0;
2436                      amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) {
2437                         if (amt_read == -1) {
2438                                 warn("error reading data from stdin");
2439                                 error = 1;
2440                                 goto scsicmd_bailout;
2441                         }
2442                         amt_to_read -= amt_read;
2443                         buf_ptr += amt_read;
2444                 }
2445         }
2446
2447         if (arglist & CAM_ARG_ERR_RECOVER)
2448                 flags |= CAM_PASS_ERR_RECOVER;
2449
2450         /* Disable freezing the device queue */
2451         flags |= CAM_DEV_QFRZDIS;
2452
2453         if (cdb_len) {
2454                 /*
2455                  * This is taken from the SCSI-3 draft spec.
2456                  * (T10/1157D revision 0.3)
2457                  * The top 3 bits of an opcode are the group code.
2458                  * The next 5 bits are the command code.
2459                  * Group 0:  six byte commands
2460                  * Group 1:  ten byte commands
2461                  * Group 2:  ten byte commands
2462                  * Group 3:  reserved
2463                  * Group 4:  sixteen byte commands
2464                  * Group 5:  twelve byte commands
2465                  * Group 6:  vendor specific
2466                  * Group 7:  vendor specific
2467                  */
2468                 switch((cdb[0] >> 5) & 0x7) {
2469                         case 0:
2470                                 cdb_len = 6;
2471                                 break;
2472                         case 1:
2473                         case 2:
2474                                 cdb_len = 10;
2475                                 break;
2476                         case 3:
2477                         case 6:
2478                         case 7:
2479                                 /* computed by buff_encode_visit */
2480                                 break;
2481                         case 4:
2482                                 cdb_len = 16;
2483                                 break;
2484                         case 5:
2485                                 cdb_len = 12;
2486                                 break;
2487                 }
2488
2489                 /*
2490                  * We should probably use csio_build_visit or something like that
2491                  * here, but it's easier to encode arguments as you go.  The
2492                  * alternative would be skipping the CDB argument and then encoding
2493                  * it here, since we've got the data buffer argument by now.
2494                  */
2495                 bcopy(cdb, &ccb->csio.cdb_io.cdb_bytes, cdb_len);
2496
2497                 cam_fill_csio(&ccb->csio,
2498                       /*retries*/ retry_count,
2499                       /*cbfcnp*/ NULL,
2500                       /*flags*/ flags,
2501                       /*tag_action*/ MSG_SIMPLE_Q_TAG,
2502                       /*data_ptr*/ data_ptr,
2503                       /*dxfer_len*/ data_bytes,
2504                       /*sense_len*/ SSD_FULL_SIZE,
2505                       /*cdb_len*/ cdb_len,
2506                       /*timeout*/ timeout ? timeout : 5000);
2507         } else {
2508                 atacmd_len = 12;
2509                 bcopy(atacmd, &ccb->ataio.cmd.command, atacmd_len);
2510                 if (need_res)
2511                         ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT;
2512                 if (dmacmd)
2513                         ccb->ataio.cmd.flags |= CAM_ATAIO_DMA;
2514                 if (fpdmacmd)
2515                         ccb->ataio.cmd.flags |= CAM_ATAIO_FPDMA;
2516
2517                 cam_fill_ataio(&ccb->ataio,
2518                       /*retries*/ retry_count,
2519                       /*cbfcnp*/ NULL,
2520                       /*flags*/ flags,
2521                       /*tag_action*/ 0,
2522                       /*data_ptr*/ data_ptr,
2523                       /*dxfer_len*/ data_bytes,
2524                       /*timeout*/ timeout ? timeout : 5000);
2525         }
2526
2527         if (((retval = cam_send_ccb(device, ccb)) < 0)
2528          || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
2529                 const char warnstr[] = "error sending command";
2530
2531                 if (retval < 0)
2532                         warn(warnstr);
2533                 else
2534                         warnx(warnstr);
2535
2536                 if (arglist & CAM_ARG_VERBOSE) {
2537                         cam_error_print(device, ccb, CAM_ESF_ALL,
2538                                         CAM_EPF_ALL, stderr);
2539                 }
2540
2541                 error = 1;
2542                 goto scsicmd_bailout;
2543         }
2544
2545         if (atacmd_len && need_res) {
2546                 if (fd_res == 0) {
2547                         buff_decode_visit(&ccb->ataio.res.status, 11, resstr,
2548                                           arg_put, NULL);
2549                         fprintf(stdout, "\n");
2550                 } else {
2551                         fprintf(stdout,
2552                             "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
2553                             ccb->ataio.res.status,
2554                             ccb->ataio.res.error,
2555                             ccb->ataio.res.lba_low,
2556                             ccb->ataio.res.lba_mid,
2557                             ccb->ataio.res.lba_high,
2558                             ccb->ataio.res.device,
2559                             ccb->ataio.res.lba_low_exp,
2560                             ccb->ataio.res.lba_mid_exp,
2561                             ccb->ataio.res.lba_high_exp,
2562                             ccb->ataio.res.sector_count,
2563                             ccb->ataio.res.sector_count_exp);
2564                         fflush(stdout);
2565                 }
2566         }
2567
2568         if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
2569          && (arglist & CAM_ARG_CMD_IN)
2570          && (data_bytes > 0)) {
2571                 if (fd_data == 0) {
2572                         buff_decode_visit(data_ptr, data_bytes, datastr,
2573                                           arg_put, NULL);
2574                         fprintf(stdout, "\n");
2575                 } else {
2576                         ssize_t amt_written;
2577                         int amt_to_write = data_bytes;
2578                         u_int8_t *buf_ptr = data_ptr;
2579
2580                         for (amt_written = 0; (amt_to_write > 0) &&
2581                              (amt_written =write(1, buf_ptr,amt_to_write))> 0;){
2582                                 amt_to_write -= amt_written;
2583                                 buf_ptr += amt_written;
2584                         }
2585                         if (amt_written == -1) {
2586                                 warn("error writing data to stdout");
2587                                 error = 1;
2588                                 goto scsicmd_bailout;
2589                         } else if ((amt_written == 0)
2590                                 && (amt_to_write > 0)) {
2591                                 warnx("only wrote %u bytes out of %u",
2592                                       data_bytes - amt_to_write, data_bytes);
2593                         }
2594                 }
2595         }
2596
2597 scsicmd_bailout:
2598
2599         if ((data_bytes > 0) && (data_ptr != NULL))
2600                 free(data_ptr);
2601
2602         cam_freeccb(ccb);
2603
2604         return(error);
2605 }
2606
2607 static int
2608 camdebug(int argc, char **argv, char *combinedopt)
2609 {
2610         int c, fd;
2611         int bus = -1, target = -1, lun = -1;
2612         char *tstr, *tmpstr = NULL;
2613         union ccb ccb;
2614         int error = 0;
2615
2616         bzero(&ccb, sizeof(union ccb));
2617
2618         while ((c = getopt(argc, argv, combinedopt)) != -1) {
2619                 switch(c) {
2620                 case 'I':
2621                         arglist |= CAM_ARG_DEBUG_INFO;
2622                         ccb.cdbg.flags |= CAM_DEBUG_INFO;
2623                         break;
2624                 case 'P':
2625                         arglist |= CAM_ARG_DEBUG_PERIPH;
2626                         ccb.cdbg.flags |= CAM_DEBUG_PERIPH;
2627                         break;
2628                 case 'S':
2629                         arglist |= CAM_ARG_DEBUG_SUBTRACE;
2630                         ccb.cdbg.flags |= CAM_DEBUG_SUBTRACE;
2631                         break;
2632                 case 'T':
2633                         arglist |= CAM_ARG_DEBUG_TRACE;
2634                         ccb.cdbg.flags |= CAM_DEBUG_TRACE;
2635                         break;
2636                 case 'X':
2637                         arglist |= CAM_ARG_DEBUG_XPT;
2638                         ccb.cdbg.flags |= CAM_DEBUG_XPT;
2639                         break;
2640                 case 'c':
2641                         arglist |= CAM_ARG_DEBUG_CDB;
2642                         ccb.cdbg.flags |= CAM_DEBUG_CDB;
2643                         break;
2644                 case 'p':
2645                         arglist |= CAM_ARG_DEBUG_PROBE;
2646                         ccb.cdbg.flags |= CAM_DEBUG_PROBE;
2647                         break;
2648                 default:
2649                         break;
2650                 }
2651         }
2652
2653         if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
2654                 warnx("error opening transport layer device %s", XPT_DEVICE);
2655                 warn("%s", XPT_DEVICE);
2656                 return(1);
2657         }
2658         argc -= optind;
2659         argv += optind;
2660
2661         if (argc <= 0) {
2662                 warnx("you must specify \"off\", \"all\" or a bus,");
2663                 warnx("bus:target, or bus:target:lun");
2664                 close(fd);
2665                 return(1);
2666         }
2667
2668         tstr = *argv;
2669
2670         while (isspace(*tstr) && (*tstr != '\0'))
2671                 tstr++;
2672
2673         if (strncmp(tstr, "off", 3) == 0) {
2674                 ccb.cdbg.flags = CAM_DEBUG_NONE;
2675                 arglist &= ~(CAM_ARG_DEBUG_INFO|CAM_ARG_DEBUG_PERIPH|
2676                              CAM_ARG_DEBUG_TRACE|CAM_ARG_DEBUG_SUBTRACE|
2677                              CAM_ARG_DEBUG_XPT|CAM_ARG_DEBUG_PROBE);
2678         } else if (strncmp(tstr, "all", 3) != 0) {
2679                 tmpstr = (char *)strtok(tstr, ":");
2680                 if ((tmpstr != NULL) && (*tmpstr != '\0')){
2681                         bus = strtol(tmpstr, NULL, 0);
2682                         arglist |= CAM_ARG_BUS;
2683                         tmpstr = (char *)strtok(NULL, ":");
2684                         if ((tmpstr != NULL) && (*tmpstr != '\0')){
2685                                 target = strtol(tmpstr, NULL, 0);
2686                                 arglist |= CAM_ARG_TARGET;
2687                                 tmpstr = (char *)strtok(NULL, ":");
2688                                 if ((tmpstr != NULL) && (*tmpstr != '\0')){
2689                                         lun = strtol(tmpstr, NULL, 0);
2690                                         arglist |= CAM_ARG_LUN;
2691                                 }
2692                         }
2693                 } else {
2694                         error = 1;
2695                         warnx("you must specify \"all\", \"off\", or a bus,");
2696                         warnx("bus:target, or bus:target:lun to debug");
2697                 }
2698         }
2699
2700         if (error == 0) {
2701
2702                 ccb.ccb_h.func_code = XPT_DEBUG;
2703                 ccb.ccb_h.path_id = bus;
2704                 ccb.ccb_h.target_id = target;
2705                 ccb.ccb_h.target_lun = lun;
2706
2707                 if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
2708                         warn("CAMIOCOMMAND ioctl failed");
2709                         error = 1;
2710                 }
2711
2712                 if (error == 0) {
2713                         if ((ccb.ccb_h.status & CAM_STATUS_MASK) ==
2714                              CAM_FUNC_NOTAVAIL) {
2715                                 warnx("CAM debugging not available");
2716                                 warnx("you need to put options CAMDEBUG in"
2717                                       " your kernel config file!");
2718                                 error = 1;
2719                         } else if ((ccb.ccb_h.status & CAM_STATUS_MASK) !=
2720                                     CAM_REQ_CMP) {
2721                                 warnx("XPT_DEBUG CCB failed with status %#x",
2722                                       ccb.ccb_h.status);
2723                                 error = 1;
2724                         } else {
2725                                 if (ccb.cdbg.flags == CAM_DEBUG_NONE) {
2726                                         fprintf(stderr,
2727                                                 "Debugging turned off\n");
2728                                 } else {
2729                                         fprintf(stderr,
2730                                                 "Debugging enabled for "
2731                                                 "%d:%d:%d\n",
2732                                                 bus, target, lun);
2733                                 }
2734                         }
2735                 }
2736                 close(fd);
2737         }
2738
2739         return(error);
2740 }
2741
2742 static int
2743 tagcontrol(struct cam_device *device, int argc, char **argv,
2744            char *combinedopt)
2745 {
2746         int c;
2747         union ccb *ccb;
2748         int numtags = -1;
2749         int retval = 0;
2750         int quiet = 0;
2751         char pathstr[1024];
2752
2753         ccb = cam_getccb(device);
2754
2755         if (ccb == NULL) {
2756                 warnx("tagcontrol: error allocating ccb");
2757                 return(1);
2758         }
2759
2760         while ((c = getopt(argc, argv, combinedopt)) != -1) {
2761                 switch(c) {
2762                 case 'N':
2763                         numtags = strtol(optarg, NULL, 0);
2764                         if (numtags < 0) {
2765                                 warnx("tag count %d is < 0", numtags);
2766                                 retval = 1;
2767                                 goto tagcontrol_bailout;
2768                         }
2769                         break;
2770                 case 'q':
2771                         quiet++;
2772                         break;
2773                 default:
2774                         break;
2775                 }
2776         }
2777
2778         cam_path_string(device, pathstr, sizeof(pathstr));
2779
2780         if (numtags >= 0) {
2781                 bzero(&(&ccb->ccb_h)[1],
2782                       sizeof(struct ccb_relsim) - sizeof(struct ccb_hdr));
2783                 ccb->ccb_h.func_code = XPT_REL_SIMQ;
2784                 ccb->ccb_h.flags = CAM_DEV_QFREEZE;
2785                 ccb->crs.release_flags = RELSIM_ADJUST_OPENINGS;
2786                 ccb->crs.openings = numtags;
2787
2788
2789                 if (cam_send_ccb(device, ccb) < 0) {
2790                         perror("error sending XPT_REL_SIMQ CCB");
2791                         retval = 1;
2792                         goto tagcontrol_bailout;
2793                 }
2794
2795                 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2796                         warnx("XPT_REL_SIMQ CCB failed");
2797                         cam_error_print(device, ccb, CAM_ESF_ALL,
2798                                         CAM_EPF_ALL, stderr);
2799                         retval = 1;
2800                         goto tagcontrol_bailout;
2801                 }
2802
2803
2804                 if (quiet == 0)
2805                         fprintf(stdout, "%stagged openings now %d\n",
2806                                 pathstr, ccb->crs.openings);
2807         }
2808
2809         bzero(&(&ccb->ccb_h)[1],
2810               sizeof(struct ccb_getdevstats) - sizeof(struct ccb_hdr));
2811
2812         ccb->ccb_h.func_code = XPT_GDEV_STATS;
2813
2814         if (cam_send_ccb(device, ccb) < 0) {
2815                 perror("error sending XPT_GDEV_STATS CCB");
2816                 retval = 1;
2817                 goto tagcontrol_bailout;
2818         }
2819
2820         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2821                 warnx("XPT_GDEV_STATS CCB failed");
2822                 cam_error_print(device, ccb, CAM_ESF_ALL,
2823                                 CAM_EPF_ALL, stderr);
2824                 retval = 1;
2825                 goto tagcontrol_bailout;
2826         }
2827
2828         if (arglist & CAM_ARG_VERBOSE) {
2829                 fprintf(stdout, "%s", pathstr);
2830                 fprintf(stdout, "dev_openings  %d\n", ccb->cgds.dev_openings);
2831                 fprintf(stdout, "%s", pathstr);
2832                 fprintf(stdout, "dev_active    %d\n", ccb->cgds.dev_active);
2833                 fprintf(stdout, "%s", pathstr);
2834                 fprintf(stdout, "devq_openings %d\n", ccb->cgds.devq_openings);
2835                 fprintf(stdout, "%s", pathstr);
2836                 fprintf(stdout, "devq_queued   %d\n", ccb->cgds.devq_queued);
2837                 fprintf(stdout, "%s", pathstr);
2838                 fprintf(stdout, "held          %d\n", ccb->cgds.held);
2839                 fprintf(stdout, "%s", pathstr);
2840                 fprintf(stdout, "mintags       %d\n", ccb->cgds.mintags);
2841                 fprintf(stdout, "%s", pathstr);
2842                 fprintf(stdout, "maxtags       %d\n", ccb->cgds.maxtags);
2843         } else {
2844                 if (quiet == 0) {
2845                         fprintf(stdout, "%s", pathstr);
2846                         fprintf(stdout, "device openings: ");
2847                 }
2848                 fprintf(stdout, "%d\n", ccb->cgds.dev_openings +
2849                         ccb->cgds.dev_active);
2850         }
2851
2852 tagcontrol_bailout:
2853
2854         cam_freeccb(ccb);
2855         return(retval);
2856 }
2857
2858 static void
2859 cts_print(struct cam_device *device, struct ccb_trans_settings *cts)
2860 {
2861         char pathstr[1024];
2862
2863         cam_path_string(device, pathstr, sizeof(pathstr));
2864
2865         if (cts->transport == XPORT_SPI) {
2866                 struct ccb_trans_settings_spi *spi =
2867                     &cts->xport_specific.spi;
2868
2869                 if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) {
2870
2871                         fprintf(stdout, "%ssync parameter: %d\n", pathstr,
2872                                 spi->sync_period);
2873
2874                         if (spi->sync_offset != 0) {
2875                                 u_int freq;
2876
2877                                 freq = scsi_calc_syncsrate(spi->sync_period);
2878                                 fprintf(stdout, "%sfrequency: %d.%03dMHz\n",
2879                                         pathstr, freq / 1000, freq % 1000);
2880                         }
2881                 }
2882
2883                 if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) {
2884                         fprintf(stdout, "%soffset: %d\n", pathstr,
2885                             spi->sync_offset);
2886                 }
2887
2888                 if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) {
2889                         fprintf(stdout, "%sbus width: %d bits\n", pathstr,
2890                                 (0x01 << spi->bus_width) * 8);
2891                 }
2892
2893                 if (spi->valid & CTS_SPI_VALID_DISC) {
2894                         fprintf(stdout, "%sdisconnection is %s\n", pathstr,
2895                                 (spi->flags & CTS_SPI_FLAGS_DISC_ENB) ?
2896                                 "enabled" : "disabled");
2897                 }
2898         }
2899         if (cts->transport == XPORT_FC) {
2900                 struct ccb_trans_settings_fc *fc =
2901                     &cts->xport_specific.fc;
2902
2903                 if (fc->valid & CTS_FC_VALID_WWNN)
2904                         fprintf(stdout, "%sWWNN: 0x%llx", pathstr,
2905                             (long long) fc->wwnn);
2906                 if (fc->valid & CTS_FC_VALID_WWPN)
2907                         fprintf(stdout, "%sWWPN: 0x%llx", pathstr,
2908                             (long long) fc->wwpn);
2909                 if (fc->valid & CTS_FC_VALID_PORT)
2910                         fprintf(stdout, "%sPortID: 0x%x", pathstr, fc->port);
2911                 if (fc->valid & CTS_FC_VALID_SPEED)
2912                         fprintf(stdout, "%stransfer speed: %d.%03dMB/s\n",
2913                             pathstr, fc->bitrate / 1000, fc->bitrate % 1000);
2914         }
2915         if (cts->transport == XPORT_SAS) {
2916                 struct ccb_trans_settings_sas *sas =
2917                     &cts->xport_specific.sas;
2918
2919                 if (sas->valid & CTS_SAS_VALID_SPEED)
2920                         fprintf(stdout, "%stransfer speed: %d.%03dMB/s\n",
2921                             pathstr, sas->bitrate / 1000, sas->bitrate % 1000);
2922         }
2923         if (cts->transport == XPORT_ATA) {
2924                 struct ccb_trans_settings_pata *pata =
2925                     &cts->xport_specific.ata;
2926
2927                 if ((pata->valid & CTS_ATA_VALID_MODE) != 0) {
2928                         fprintf(stdout, "%sATA mode: %s\n", pathstr,
2929                                 ata_mode2string(pata->mode));
2930                 }
2931                 if ((pata->valid & CTS_ATA_VALID_ATAPI) != 0) {
2932                         fprintf(stdout, "%sATAPI packet length: %d\n", pathstr,
2933                                 pata->atapi);
2934                 }
2935                 if ((pata->valid & CTS_ATA_VALID_BYTECOUNT) != 0) {
2936                         fprintf(stdout, "%sPIO transaction length: %d\n",
2937                                 pathstr, pata->bytecount);
2938                 }
2939         }
2940         if (cts->transport == XPORT_SATA) {
2941                 struct ccb_trans_settings_sata *sata =
2942                     &cts->xport_specific.sata;
2943
2944                 if ((sata->valid & CTS_SATA_VALID_REVISION) != 0) {
2945                         fprintf(stdout, "%sSATA revision: %d.x\n", pathstr,
2946                                 sata->revision);
2947                 }
2948                 if ((sata->valid & CTS_SATA_VALID_MODE) != 0) {
2949                         fprintf(stdout, "%sATA mode: %s\n", pathstr,
2950                                 ata_mode2string(sata->mode));
2951                 }
2952                 if ((sata->valid & CTS_SATA_VALID_ATAPI) != 0) {
2953                         fprintf(stdout, "%sATAPI packet length: %d\n", pathstr,
2954                                 sata->atapi);
2955                 }
2956                 if ((sata->valid & CTS_SATA_VALID_BYTECOUNT) != 0) {
2957                         fprintf(stdout, "%sPIO transaction length: %d\n",
2958                                 pathstr, sata->bytecount);
2959                 }
2960                 if ((sata->valid & CTS_SATA_VALID_PM) != 0) {
2961                         fprintf(stdout, "%sPMP presence: %d\n", pathstr,
2962                                 sata->pm_present);
2963                 }
2964                 if ((sata->valid & CTS_SATA_VALID_TAGS) != 0) {
2965                         fprintf(stdout, "%sNumber of tags: %d\n", pathstr,
2966                                 sata->tags);
2967                 }
2968                 if ((sata->valid & CTS_SATA_VALID_CAPS) != 0) {
2969                         fprintf(stdout, "%sSATA capabilities: %08x\n", pathstr,
2970                                 sata->caps);
2971                 }
2972         }
2973         if (cts->protocol == PROTO_ATA) {
2974                 struct ccb_trans_settings_ata *ata=
2975                     &cts->proto_specific.ata;
2976
2977                 if (ata->valid & CTS_ATA_VALID_TQ) {
2978                         fprintf(stdout, "%stagged queueing: %s\n", pathstr,
2979                                 (ata->flags & CTS_ATA_FLAGS_TAG_ENB) ?
2980                                 "enabled" : "disabled");
2981                 }
2982         }
2983         if (cts->protocol == PROTO_SCSI) {
2984                 struct ccb_trans_settings_scsi *scsi=
2985                     &cts->proto_specific.scsi;
2986
2987                 if (scsi->valid & CTS_SCSI_VALID_TQ) {
2988                         fprintf(stdout, "%stagged queueing: %s\n", pathstr,
2989                                 (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) ?
2990                                 "enabled" : "disabled");
2991                 }
2992         }
2993
2994 }
2995
2996 /*
2997  * Get a path inquiry CCB for the specified device.
2998  */
2999 static int
3000 get_cpi(struct cam_device *device, struct ccb_pathinq *cpi)
3001 {
3002         union ccb *ccb;
3003         int retval = 0;
3004
3005         ccb = cam_getccb(device);
3006         if (ccb == NULL) {
3007                 warnx("get_cpi: couldn't allocate CCB");
3008                 return(1);
3009         }
3010         bzero(&(&ccb->ccb_h)[1],
3011               sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr));
3012         ccb->ccb_h.func_code = XPT_PATH_INQ;
3013         if (cam_send_ccb(device, ccb) < 0) {
3014                 warn("get_cpi: error sending Path Inquiry CCB");
3015                 if (arglist & CAM_ARG_VERBOSE)
3016                         cam_error_print(device, ccb, CAM_ESF_ALL,
3017                                         CAM_EPF_ALL, stderr);
3018                 retval = 1;
3019                 goto get_cpi_bailout;
3020         }
3021         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3022                 if (arglist & CAM_ARG_VERBOSE)
3023                         cam_error_print(device, ccb, CAM_ESF_ALL,
3024                                         CAM_EPF_ALL, stderr);
3025                 retval = 1;
3026                 goto get_cpi_bailout;
3027         }
3028         bcopy(&ccb->cpi, cpi, sizeof(struct ccb_pathinq));
3029
3030 get_cpi_bailout:
3031         cam_freeccb(ccb);
3032         return(retval);
3033 }
3034
3035 /*
3036  * Get a get device CCB for the specified device.
3037  */
3038 static int
3039 get_cgd(struct cam_device *device, struct ccb_getdev *cgd)
3040 {
3041         union ccb *ccb;
3042         int retval = 0;
3043
3044         ccb = cam_getccb(device);
3045         if (ccb == NULL) {
3046                 warnx("get_cgd: couldn't allocate CCB");
3047                 return(1);
3048         }
3049         bzero(&(&ccb->ccb_h)[1],
3050               sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr));
3051         ccb->ccb_h.func_code = XPT_GDEV_TYPE;
3052         if (cam_send_ccb(device, ccb) < 0) {
3053                 warn("get_cgd: error sending Path Inquiry CCB");
3054                 if (arglist & CAM_ARG_VERBOSE)
3055                         cam_error_print(device, ccb, CAM_ESF_ALL,
3056                                         CAM_EPF_ALL, stderr);
3057                 retval = 1;
3058                 goto get_cgd_bailout;
3059         }
3060         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3061                 if (arglist & CAM_ARG_VERBOSE)
3062                         cam_error_print(device, ccb, CAM_ESF_ALL,
3063                                         CAM_EPF_ALL, stderr);
3064                 retval = 1;
3065                 goto get_cgd_bailout;
3066         }
3067         bcopy(&ccb->cgd, cgd, sizeof(struct ccb_getdev));
3068
3069 get_cgd_bailout:
3070         cam_freeccb(ccb);
3071         return(retval);
3072 }
3073
3074 /* return the type of disk (really the command type) */
3075 static const char *
3076 get_disk_type(struct cam_device *device)
3077 {
3078         struct ccb_getdev       cgd;
3079
3080         (void) memset(&cgd, 0x0, sizeof(cgd));
3081         get_cgd(device, &cgd);
3082         switch(cgd.protocol) {
3083         case PROTO_SCSI:
3084                 return "scsi";
3085         case PROTO_ATA:
3086         case PROTO_ATAPI:
3087         case PROTO_SATAPM:
3088                 return "ata";
3089         default:
3090                 return "unknown";
3091         }
3092 }
3093
3094 static void
3095 cpi_print(struct ccb_pathinq *cpi)
3096 {
3097         char adapter_str[1024];
3098         int i;
3099
3100         snprintf(adapter_str, sizeof(adapter_str),
3101                  "%s%d:", cpi->dev_name, cpi->unit_number);
3102
3103         fprintf(stdout, "%s SIM/HBA version: %d\n", adapter_str,
3104                 cpi->version_num);
3105
3106         for (i = 1; i < 0xff; i = i << 1) {
3107                 const char *str;
3108
3109                 if ((i & cpi->hba_inquiry) == 0)
3110                         continue;
3111
3112                 fprintf(stdout, "%s supports ", adapter_str);
3113
3114                 switch(i) {
3115                 case PI_MDP_ABLE:
3116                         str = "MDP message";
3117                         break;
3118                 case PI_WIDE_32:
3119                         str = "32 bit wide SCSI";
3120                         break;
3121                 case PI_WIDE_16:
3122                         str = "16 bit wide SCSI";
3123                         break;
3124                 case PI_SDTR_ABLE:
3125                         str = "SDTR message";
3126                         break;
3127                 case PI_LINKED_CDB:
3128                         str = "linked CDBs";
3129                         break;
3130                 case PI_TAG_ABLE:
3131                         str = "tag queue messages";
3132                         break;
3133                 case PI_SOFT_RST:
3134                         str = "soft reset alternative";
3135                         break;
3136                 case PI_SATAPM:
3137                         str = "SATA Port Multiplier";
3138                         break;
3139                 default:
3140                         str = "unknown PI bit set";
3141                         break;
3142                 }
3143                 fprintf(stdout, "%s\n", str);
3144         }
3145
3146         for (i = 1; i < 0xff; i = i << 1) {
3147                 const char *str;
3148
3149                 if ((i & cpi->hba_misc) == 0)
3150                         continue;
3151
3152                 fprintf(stdout, "%s ", adapter_str);
3153
3154                 switch(i) {
3155                 case PIM_SCANHILO:
3156                         str = "bus scans from high ID to low ID";
3157                         break;
3158                 case PIM_NOREMOVE:
3159                         str = "removable devices not included in scan";
3160                         break;
3161                 case PIM_NOINITIATOR:
3162                         str = "initiator role not supported";
3163                         break;
3164                 case PIM_NOBUSRESET:
3165                         str = "user has disabled initial BUS RESET or"
3166                               " controller is in target/mixed mode";
3167                         break;
3168                 case PIM_NO_6_BYTE:
3169                         str = "do not send 6-byte commands";
3170                         break;
3171                 case PIM_SEQSCAN:
3172                         str = "scan bus sequentially";
3173                         break;
3174                 default:
3175                         str = "unknown PIM bit set";
3176                         break;
3177                 }
3178                 fprintf(stdout, "%s\n", str);
3179         }
3180
3181         for (i = 1; i < 0xff; i = i << 1) {
3182                 const char *str;
3183
3184                 if ((i & cpi->target_sprt) == 0)
3185                         continue;
3186
3187                 fprintf(stdout, "%s supports ", adapter_str);
3188                 switch(i) {
3189                 case PIT_PROCESSOR:
3190                         str = "target mode processor mode";
3191                         break;
3192                 case PIT_PHASE:
3193                         str = "target mode phase cog. mode";
3194                         break;
3195                 case PIT_DISCONNECT:
3196                         str = "disconnects in target mode";
3197                         break;
3198                 case PIT_TERM_IO:
3199                         str = "terminate I/O message in target mode";
3200                         break;
3201                 case PIT_GRP_6:
3202                         str = "group 6 commands in target mode";
3203                         break;
3204                 case PIT_GRP_7:
3205                         str = "group 7 commands in target mode";
3206                         break;
3207                 default:
3208                         str = "unknown PIT bit set";
3209                         break;
3210                 }
3211
3212                 fprintf(stdout, "%s\n", str);
3213         }
3214         fprintf(stdout, "%s HBA engine count: %d\n", adapter_str,
3215                 cpi->hba_eng_cnt);
3216         fprintf(stdout, "%s maximum target: %d\n", adapter_str,
3217                 cpi->max_target);
3218         fprintf(stdout, "%s maximum LUN: %d\n", adapter_str,
3219                 cpi->max_lun);
3220         fprintf(stdout, "%s highest path ID in subsystem: %d\n",
3221                 adapter_str, cpi->hpath_id);
3222         fprintf(stdout, "%s initiator ID: %d\n", adapter_str,
3223                 cpi->initiator_id);
3224         fprintf(stdout, "%s SIM vendor: %s\n", adapter_str, cpi->sim_vid);
3225         fprintf(stdout, "%s HBA vendor: %s\n", adapter_str, cpi->hba_vid);
3226         fprintf(stdout, "%s HBA vendor ID: 0x%04x\n",
3227             adapter_str, cpi->hba_vendor);
3228         fprintf(stdout, "%s HBA device ID: 0x%04x\n",
3229             adapter_str, cpi->hba_device);
3230         fprintf(stdout, "%s HBA subvendor ID: 0x%04x\n",
3231             adapter_str, cpi->hba_subvendor);
3232         fprintf(stdout, "%s HBA subdevice ID: 0x%04x\n",
3233             adapter_str, cpi->hba_subdevice);
3234         fprintf(stdout, "%s bus ID: %d\n", adapter_str, cpi->bus_id);
3235         fprintf(stdout, "%s base transfer speed: ", adapter_str);
3236         if (cpi->base_transfer_speed > 1000)
3237                 fprintf(stdout, "%d.%03dMB/sec\n",
3238                         cpi->base_transfer_speed / 1000,
3239                         cpi->base_transfer_speed % 1000);
3240         else
3241                 fprintf(stdout, "%dKB/sec\n",
3242                         (cpi->base_transfer_speed % 1000) * 1000);
3243         fprintf(stdout, "%s maximum transfer size: %u bytes\n",
3244             adapter_str, cpi->maxio);
3245 }
3246
3247 static int
3248 get_print_cts(struct cam_device *device, int user_settings, int quiet,
3249               struct ccb_trans_settings *cts)
3250 {
3251         int retval;
3252         union ccb *ccb;
3253
3254         retval = 0;
3255         ccb = cam_getccb(device);
3256
3257         if (ccb == NULL) {
3258                 warnx("get_print_cts: error allocating ccb");
3259                 return(1);
3260         }
3261
3262         bzero(&(&ccb->ccb_h)[1],
3263               sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr));
3264
3265         ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
3266
3267         if (user_settings == 0)
3268                 ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS;
3269         else
3270                 ccb->cts.type = CTS_TYPE_USER_SETTINGS;
3271
3272         if (cam_send_ccb(device, ccb) < 0) {
3273                 perror("error sending XPT_GET_TRAN_SETTINGS CCB");
3274                 if (arglist & CAM_ARG_VERBOSE)
3275                         cam_error_print(device, ccb, CAM_ESF_ALL,
3276                                         CAM_EPF_ALL, stderr);
3277                 retval = 1;
3278                 goto get_print_cts_bailout;
3279         }
3280
3281         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3282                 warnx("XPT_GET_TRANS_SETTINGS CCB failed");
3283                 if (arglist & CAM_ARG_VERBOSE)
3284                         cam_error_print(device, ccb, CAM_ESF_ALL,
3285                                         CAM_EPF_ALL, stderr);
3286                 retval = 1;
3287                 goto get_print_cts_bailout;
3288         }
3289
3290         if (quiet == 0)
3291                 cts_print(device, &ccb->cts);
3292
3293         if (cts != NULL)
3294                 bcopy(&ccb->cts, cts, sizeof(struct ccb_trans_settings));
3295
3296 get_print_cts_bailout:
3297
3298         cam_freeccb(ccb);
3299
3300         return(retval);
3301 }
3302
3303 static int
3304 ratecontrol(struct cam_device *device, int retry_count, int timeout,
3305             int argc, char **argv, char *combinedopt)
3306 {
3307         int c;
3308         union ccb *ccb;
3309         int user_settings = 0;
3310         int retval = 0;
3311         int disc_enable = -1, tag_enable = -1;
3312         int mode = -1;
3313         int offset = -1;
3314         double syncrate = -1;
3315         int bus_width = -1;
3316         int quiet = 0;
3317         int change_settings = 0, send_tur = 0;
3318         struct ccb_pathinq cpi;
3319
3320         ccb = cam_getccb(device);
3321         if (ccb == NULL) {
3322                 warnx("ratecontrol: error allocating ccb");
3323                 return(1);
3324         }
3325         while ((c = getopt(argc, argv, combinedopt)) != -1) {
3326                 switch(c){
3327                 case 'a':
3328                         send_tur = 1;
3329                         break;
3330                 case 'c':
3331                         user_settings = 0;
3332                         break;
3333                 case 'D':
3334                         if (strncasecmp(optarg, "enable", 6) == 0)
3335                                 disc_enable = 1;
3336                         else if (strncasecmp(optarg, "disable", 7) == 0)
3337                                 disc_enable = 0;
3338                         else {
3339                                 warnx("-D argument \"%s\" is unknown", optarg);
3340                                 retval = 1;
3341                                 goto ratecontrol_bailout;
3342                         }
3343                         change_settings = 1;
3344                         break;
3345                 case 'M':
3346                         mode = ata_string2mode(optarg);
3347                         if (mode < 0) {
3348                                 warnx("unknown mode '%s'", optarg);
3349                                 retval = 1;
3350                                 goto ratecontrol_bailout;
3351                         }
3352                         change_settings = 1;
3353                         break;
3354                 case 'O':
3355                         offset = strtol(optarg, NULL, 0);
3356                         if (offset < 0) {
3357                                 warnx("offset value %d is < 0", offset);
3358                                 retval = 1;
3359                                 goto ratecontrol_bailout;
3360                         }
3361                         change_settings = 1;
3362                         break;
3363                 case 'q':
3364                         quiet++;
3365                         break;
3366                 case 'R':
3367                         syncrate = atof(optarg);
3368                         if (syncrate < 0) {
3369                                 warnx("sync rate %f is < 0", syncrate);
3370                                 retval = 1;
3371                                 goto ratecontrol_bailout;
3372                         }
3373                         change_settings = 1;
3374                         break;
3375                 case 'T':
3376                         if (strncasecmp(optarg, "enable", 6) == 0)
3377                                 tag_enable = 1;
3378                         else if (strncasecmp(optarg, "disable", 7) == 0)
3379                                 tag_enable = 0;
3380                         else {
3381                                 warnx("-T argument \"%s\" is unknown", optarg);
3382                                 retval = 1;
3383                                 goto ratecontrol_bailout;
3384                         }
3385                         change_settings = 1;
3386                         break;
3387                 case 'U':
3388                         user_settings = 1;
3389                         break;
3390                 case 'W':
3391                         bus_width = strtol(optarg, NULL, 0);
3392                         if (bus_width < 0) {
3393                                 warnx("bus width %d is < 0", bus_width);
3394                                 retval = 1;
3395                                 goto ratecontrol_bailout;
3396                         }
3397                         change_settings = 1;
3398                         break;
3399                 default:
3400                         break;
3401                 }
3402         }
3403         bzero(&(&ccb->ccb_h)[1],
3404               sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr));
3405         /*
3406          * Grab path inquiry information, so we can determine whether
3407          * or not the initiator is capable of the things that the user
3408          * requests.
3409          */
3410         ccb->ccb_h.func_code = XPT_PATH_INQ;
3411         if (cam_send_ccb(device, ccb) < 0) {
3412                 perror("error sending XPT_PATH_INQ CCB");
3413                 if (arglist & CAM_ARG_VERBOSE) {
3414                         cam_error_print(device, ccb, CAM_ESF_ALL,
3415                                         CAM_EPF_ALL, stderr);
3416                 }
3417                 retval = 1;
3418                 goto ratecontrol_bailout;
3419         }
3420         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3421                 warnx("XPT_PATH_INQ CCB failed");
3422                 if (arglist & CAM_ARG_VERBOSE) {
3423                         cam_error_print(device, ccb, CAM_ESF_ALL,
3424                                         CAM_EPF_ALL, stderr);
3425                 }
3426                 retval = 1;
3427                 goto ratecontrol_bailout;
3428         }
3429         bcopy(&ccb->cpi, &cpi, sizeof(struct ccb_pathinq));
3430         bzero(&(&ccb->ccb_h)[1],
3431               sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr));
3432         if (quiet == 0) {
3433                 fprintf(stdout, "%s parameters:\n",
3434                     user_settings ? "User" : "Current");
3435         }
3436         retval = get_print_cts(device, user_settings, quiet, &ccb->cts);
3437         if (retval != 0)
3438                 goto ratecontrol_bailout;
3439
3440         if (arglist & CAM_ARG_VERBOSE)
3441                 cpi_print(&cpi);
3442
3443         if (change_settings) {
3444                 int didsettings = 0;
3445                 struct ccb_trans_settings_spi *spi = NULL;
3446                 struct ccb_trans_settings_pata *pata = NULL;
3447                 struct ccb_trans_settings_sata *sata = NULL;
3448                 struct ccb_trans_settings_ata *ata = NULL;
3449                 struct ccb_trans_settings_scsi *scsi = NULL;
3450
3451                 if (ccb->cts.transport == XPORT_SPI)
3452                         spi = &ccb->cts.xport_specific.spi;
3453                 if (ccb->cts.transport == XPORT_ATA)
3454                         pata = &ccb->cts.xport_specific.ata;
3455                 if (ccb->cts.transport == XPORT_SATA)
3456                         sata = &ccb->cts.xport_specific.sata;
3457                 if (ccb->cts.protocol == PROTO_ATA)
3458                         ata = &ccb->cts.proto_specific.ata;
3459                 if (ccb->cts.protocol == PROTO_SCSI)
3460                         scsi = &ccb->cts.proto_specific.scsi;
3461                 ccb->cts.xport_specific.valid = 0;
3462                 ccb->cts.proto_specific.valid = 0;
3463                 if (spi && disc_enable != -1) {
3464                         spi->valid |= CTS_SPI_VALID_DISC;
3465                         if (disc_enable == 0)
3466                                 spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
3467                         else
3468                                 spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
3469                         didsettings++;
3470                 }
3471                 if (tag_enable != -1) {
3472                         if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0) {
3473                                 warnx("HBA does not support tagged queueing, "
3474                                       "so you cannot modify tag settings");
3475                                 retval = 1;
3476                                 goto ratecontrol_bailout;
3477                         }
3478                         if (ata) {
3479                                 ata->valid |= CTS_SCSI_VALID_TQ;
3480                                 if (tag_enable == 0)
3481                                         ata->flags &= ~CTS_ATA_FLAGS_TAG_ENB;
3482                                 else
3483                                         ata->flags |= CTS_ATA_FLAGS_TAG_ENB;
3484                                 didsettings++;
3485                         } else if (scsi) {
3486                                 scsi->valid |= CTS_SCSI_VALID_TQ;
3487                                 if (tag_enable == 0)
3488                                         scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
3489                                 else
3490                                         scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
3491                                 didsettings++;
3492                         }
3493                 }
3494                 if (spi && offset != -1) {
3495                         if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
3496                                 warnx("HBA is not capable of changing offset");
3497                                 retval = 1;
3498                                 goto ratecontrol_bailout;
3499                         }
3500                         spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
3501                         spi->sync_offset = offset;
3502                         didsettings++;
3503                 }
3504                 if (spi && syncrate != -1) {
3505                         int prelim_sync_period;
3506
3507                         if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
3508                                 warnx("HBA is not capable of changing "
3509                                       "transfer rates");
3510                                 retval = 1;
3511                                 goto ratecontrol_bailout;
3512                         }
3513                         spi->valid |= CTS_SPI_VALID_SYNC_RATE;
3514                         /*
3515                          * The sync rate the user gives us is in MHz.
3516                          * We need to translate it into KHz for this
3517                          * calculation.
3518                          */
3519                         syncrate *= 1000;
3520                         /*
3521                          * Next, we calculate a "preliminary" sync period
3522                          * in tenths of a nanosecond.
3523                          */
3524                         if (syncrate == 0)
3525                                 prelim_sync_period = 0;
3526                         else
3527                                 prelim_sync_period = 10000000 / syncrate;
3528                         spi->sync_period =
3529                                 scsi_calc_syncparam(prelim_sync_period);
3530                         didsettings++;
3531                 }
3532                 if (sata && syncrate != -1) {
3533                         if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
3534                                 warnx("HBA is not capable of changing "
3535                                       "transfer rates");
3536                                 retval = 1;
3537                                 goto ratecontrol_bailout;
3538                         }
3539                         if  (!user_settings) {
3540                                 warnx("You can modify only user rate "
3541                                     "settings for SATA");
3542                                 retval = 1;
3543                                 goto ratecontrol_bailout;
3544                         }
3545                         sata->revision = ata_speed2revision(syncrate * 100);
3546                         if (sata->revision < 0) {
3547                                 warnx("Invalid rate %f", syncrate);
3548                                 retval = 1;
3549                                 goto ratecontrol_bailout;
3550                         }
3551                         sata->valid |= CTS_SATA_VALID_REVISION;
3552                         didsettings++;
3553                 }
3554                 if ((pata || sata) && mode != -1) {
3555                         if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
3556                                 warnx("HBA is not capable of changing "
3557                                       "transfer rates");
3558                                 retval = 1;
3559                                 goto ratecontrol_bailout;
3560                         }
3561                         if  (!user_settings) {
3562                                 warnx("You can modify only user mode "
3563                                     "settings for ATA/SATA");
3564                                 retval = 1;
3565                                 goto ratecontrol_bailout;
3566                         }
3567                         if (pata) {
3568                                 pata->mode = mode;
3569                                 pata->valid |= CTS_ATA_VALID_MODE;
3570                         } else {
3571                                 sata->mode = mode;
3572                                 sata->valid |= CTS_SATA_VALID_MODE;
3573                         }
3574                         didsettings++;
3575                 }
3576                 /*
3577                  * The bus_width argument goes like this:
3578                  * 0 == 8 bit
3579                  * 1 == 16 bit
3580                  * 2 == 32 bit
3581                  * Therefore, if you shift the number of bits given on the
3582                  * command line right by 4, you should get the correct
3583                  * number.
3584                  */
3585                 if (spi && bus_width != -1) {
3586                         /*
3587                          * We might as well validate things here with a
3588                          * decipherable error message, rather than what
3589                          * will probably be an indecipherable error message
3590                          * by the time it gets back to us.
3591                          */
3592                         if ((bus_width == 16)
3593                          && ((cpi.hba_inquiry & PI_WIDE_16) == 0)) {
3594                                 warnx("HBA does not support 16 bit bus width");
3595                                 retval = 1;
3596                                 goto ratecontrol_bailout;
3597                         } else if ((bus_width == 32)
3598                                 && ((cpi.hba_inquiry & PI_WIDE_32) == 0)) {
3599                                 warnx("HBA does not support 32 bit bus width");
3600                                 retval = 1;
3601                                 goto ratecontrol_bailout;
3602                         } else if ((bus_width != 8)
3603                                 && (bus_width != 16)
3604                                 && (bus_width != 32)) {
3605                                 warnx("Invalid bus width %d", bus_width);
3606                                 retval = 1;
3607                                 goto ratecontrol_bailout;
3608                         }
3609                         spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
3610                         spi->bus_width = bus_width >> 4;
3611                         didsettings++;
3612                 }
3613                 if  (didsettings == 0) {
3614                         goto ratecontrol_bailout;
3615                 }
3616                 ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
3617                 if (cam_send_ccb(device, ccb) < 0) {
3618                         perror("error sending XPT_SET_TRAN_SETTINGS CCB");
3619                         if (arglist & CAM_ARG_VERBOSE) {
3620                                 cam_error_print(device, ccb, CAM_ESF_ALL,
3621                                                 CAM_EPF_ALL, stderr);
3622                         }
3623                         retval = 1;
3624                         goto ratecontrol_bailout;
3625                 }
3626                 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3627                         warnx("XPT_SET_TRANS_SETTINGS CCB failed");
3628                         if (arglist & CAM_ARG_VERBOSE) {
3629                                 cam_error_print(device, ccb, CAM_ESF_ALL,
3630                                                 CAM_EPF_ALL, stderr);
3631                         }
3632                         retval = 1;
3633                         goto ratecontrol_bailout;
3634                 }
3635         }
3636         if (send_tur) {
3637                 retval = testunitready(device, retry_count, timeout,
3638                                        (arglist & CAM_ARG_VERBOSE) ? 0 : 1);
3639                 /*
3640                  * If the TUR didn't succeed, just bail.
3641                  */
3642                 if (retval != 0) {
3643                         if (quiet == 0)
3644                                 fprintf(stderr, "Test Unit Ready failed\n");
3645                         goto ratecontrol_bailout;
3646                 }
3647         }
3648         if ((change_settings || send_tur) && !quiet &&
3649             (ccb->cts.transport == XPORT_ATA ||
3650              ccb->cts.transport == XPORT_SATA || send_tur)) {
3651                 fprintf(stdout, "New parameters:\n");
3652                 retval = get_print_cts(device, user_settings, 0, NULL);
3653         }
3654
3655 ratecontrol_bailout:
3656         cam_freeccb(ccb);
3657         return(retval);
3658 }
3659
3660 static int
3661 scsiformat(struct cam_device *device, int argc, char **argv,
3662            char *combinedopt, int retry_count, int timeout)
3663 {
3664         union ccb *ccb;
3665         int c;
3666         int ycount = 0, quiet = 0;
3667         int error = 0, retval = 0;
3668         int use_timeout = 10800 * 1000;
3669         int immediate = 1;
3670         struct format_defect_list_header fh;
3671         u_int8_t *data_ptr = NULL;
3672         u_int32_t dxfer_len = 0;
3673         u_int8_t byte2 = 0;
3674         int num_warnings = 0;
3675         int reportonly = 0;
3676
3677         ccb = cam_getccb(device);
3678
3679         if (ccb == NULL) {
3680                 warnx("scsiformat: error allocating ccb");
3681                 return(1);
3682         }
3683
3684         bzero(&(&ccb->ccb_h)[1],
3685               sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
3686
3687         while ((c = getopt(argc, argv, combinedopt)) != -1) {
3688                 switch(c) {
3689                 case 'q':
3690                         quiet++;
3691                         break;
3692                 case 'r':
3693                         reportonly = 1;
3694                         break;
3695                 case 'w':
3696                         immediate = 0;
3697                         break;
3698                 case 'y':
3699                         ycount++;
3700                         break;
3701                 }
3702         }
3703
3704         if (reportonly)
3705                 goto doreport;
3706
3707         if (quiet == 0) {
3708                 fprintf(stdout, "You are about to REMOVE ALL DATA from the "
3709                         "following device:\n");
3710
3711                 error = scsidoinquiry(device, argc, argv, combinedopt,
3712                                       retry_count, timeout);
3713
3714                 if (error != 0) {
3715                         warnx("scsiformat: error sending inquiry");
3716                         goto scsiformat_bailout;
3717                 }
3718         }
3719
3720         if (ycount == 0) {
3721                 if (!get_confirmation()) {
3722                         error = 1;
3723                         goto scsiformat_bailout;
3724                 }
3725         }
3726
3727         if (timeout != 0)
3728                 use_timeout = timeout;
3729
3730         if (quiet == 0) {
3731                 fprintf(stdout, "Current format timeout is %d seconds\n",
3732                         use_timeout / 1000);
3733         }
3734
3735         /*
3736          * If the user hasn't disabled questions and didn't specify a
3737          * timeout on the command line, ask them if they want the current
3738          * timeout.
3739          */
3740         if ((ycount == 0)
3741          && (timeout == 0)) {
3742                 char str[1024];
3743                 int new_timeout = 0;
3744
3745                 fprintf(stdout, "Enter new timeout in seconds or press\n"
3746                         "return to keep the current timeout [%d] ",
3747                         use_timeout / 1000);
3748
3749                 if (fgets(str, sizeof(str), stdin) != NULL) {
3750                         if (str[0] != '\0')
3751                                 new_timeout = atoi(str);
3752                 }
3753
3754                 if (new_timeout != 0) {
3755                         use_timeout = new_timeout * 1000;
3756                         fprintf(stdout, "Using new timeout value %d\n",
3757                                 use_timeout / 1000);
3758                 }
3759         }
3760
3761         /*
3762          * Keep this outside the if block below to silence any unused
3763          * variable warnings.
3764          */
3765         bzero(&fh, sizeof(fh));
3766
3767         /*
3768          * If we're in immediate mode, we've got to include the format
3769          * header
3770          */
3771         if (immediate != 0) {
3772                 fh.byte2 = FU_DLH_IMMED;
3773                 data_ptr = (u_int8_t *)&fh;
3774                 dxfer_len = sizeof(fh);
3775                 byte2 = FU_FMT_DATA;
3776         } else if (quiet == 0) {
3777                 fprintf(stdout, "Formatting...");
3778                 fflush(stdout);
3779         }
3780
3781         scsi_format_unit(&ccb->csio,
3782                          /* retries */ retry_count,
3783                          /* cbfcnp */ NULL,
3784                          /* tag_action */ MSG_SIMPLE_Q_TAG,
3785                          /* byte2 */ byte2,
3786                          /* ileave */ 0,
3787                          /* data_ptr */ data_ptr,
3788                          /* dxfer_len */ dxfer_len,
3789                          /* sense_len */ SSD_FULL_SIZE,
3790                          /* timeout */ use_timeout);
3791
3792         /* Disable freezing the device queue */
3793         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
3794
3795         if (arglist & CAM_ARG_ERR_RECOVER)
3796                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
3797
3798         if (((retval = cam_send_ccb(device, ccb)) < 0)
3799          || ((immediate == 0)
3800            && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP))) {
3801                 const char errstr[] = "error sending format command";
3802
3803                 if (retval < 0)
3804                         warn(errstr);
3805                 else
3806                         warnx(errstr);
3807
3808                 if (arglist & CAM_ARG_VERBOSE) {
3809                         cam_error_print(device, ccb, CAM_ESF_ALL,
3810                                         CAM_EPF_ALL, stderr);
3811                 }
3812                 error = 1;
3813                 goto scsiformat_bailout;
3814         }
3815
3816         /*
3817          * If we ran in non-immediate mode, we already checked for errors
3818          * above and printed out any necessary information.  If we're in
3819          * immediate mode, we need to loop through and get status
3820          * information periodically.
3821          */
3822         if (immediate == 0) {
3823                 if (quiet == 0) {
3824                         fprintf(stdout, "Format Complete\n");
3825                 }
3826                 goto scsiformat_bailout;
3827         }
3828
3829 doreport:
3830         do {
3831                 cam_status status;
3832
3833                 bzero(&(&ccb->ccb_h)[1],
3834                       sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
3835
3836                 /*
3837                  * There's really no need to do error recovery or
3838                  * retries here, since we're just going to sit in a
3839                  * loop and wait for the device to finish formatting.
3840                  */
3841                 scsi_test_unit_ready(&ccb->csio,
3842                                      /* retries */ 0,
3843                                      /* cbfcnp */ NULL,
3844                                      /* tag_action */ MSG_SIMPLE_Q_TAG,
3845                                      /* sense_len */ SSD_FULL_SIZE,
3846                                      /* timeout */ 5000);
3847
3848                 /* Disable freezing the device queue */
3849                 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
3850
3851                 retval = cam_send_ccb(device, ccb);
3852
3853                 /*
3854                  * If we get an error from the ioctl, bail out.  SCSI
3855                  * errors are expected.
3856                  */
3857                 if (retval < 0) {
3858                         warn("error sending CAMIOCOMMAND ioctl");
3859                         if (arglist & CAM_ARG_VERBOSE) {
3860                                 cam_error_print(device, ccb, CAM_ESF_ALL,
3861                                                 CAM_EPF_ALL, stderr);
3862                         }
3863                         error = 1;
3864                         goto scsiformat_bailout;
3865                 }
3866
3867                 status = ccb->ccb_h.status & CAM_STATUS_MASK;
3868
3869                 if ((status != CAM_REQ_CMP)
3870                  && (status == CAM_SCSI_STATUS_ERROR)
3871                  && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) {
3872                         struct scsi_sense_data *sense;
3873                         int error_code, sense_key, asc, ascq;
3874
3875                         sense = &ccb->csio.sense_data;
3876                         scsi_extract_sense_len(sense, ccb->csio.sense_len -
3877                             ccb->csio.sense_resid, &error_code, &sense_key,
3878                             &asc, &ascq, /*show_errors*/ 1);
3879
3880                         /*
3881                          * According to the SCSI-2 and SCSI-3 specs, a
3882                          * drive that is in the middle of a format should
3883                          * return NOT READY with an ASC of "logical unit
3884                          * not ready, format in progress".  The sense key
3885                          * specific bytes will then be a progress indicator.
3886                          */
3887                         if ((sense_key == SSD_KEY_NOT_READY)
3888                          && (asc == 0x04) && (ascq == 0x04)) {
3889                                 uint8_t sks[3];
3890
3891                                 if ((scsi_get_sks(sense, ccb->csio.sense_len -
3892                                      ccb->csio.sense_resid, sks) == 0)
3893                                  && (quiet == 0)) {
3894                                         int val;
3895                                         u_int64_t percentage;
3896
3897                                         val = scsi_2btoul(&sks[1]);
3898                                         percentage = 10000 * val;
3899
3900                                         fprintf(stdout,
3901                                                 "\rFormatting:  %ju.%02u %% "
3902                                                 "(%d/%d) done",
3903                                                 (uintmax_t)(percentage /
3904                                                 (0x10000 * 100)),
3905                                                 (unsigned)((percentage /
3906                                                 0x10000) % 100),
3907                                                 val, 0x10000);
3908                                         fflush(stdout);
3909                                 } else if ((quiet == 0)
3910                                         && (++num_warnings <= 1)) {
3911                                         warnx("Unexpected SCSI Sense Key "
3912                                               "Specific value returned "
3913                                               "during format:");
3914                                         scsi_sense_print(device, &ccb->csio,
3915                                                          stderr);
3916                                         warnx("Unable to print status "
3917                                               "information, but format will "
3918                                               "proceed.");
3919                                         warnx("will exit when format is "
3920                                               "complete");
3921                                 }
3922                                 sleep(1);
3923                         } else {
3924                                 warnx("Unexpected SCSI error during format");
3925                                 cam_error_print(device, ccb, CAM_ESF_ALL,
3926                                                 CAM_EPF_ALL, stderr);
3927                                 error = 1;
3928                                 goto scsiformat_bailout;
3929                         }
3930
3931                 } else if (status != CAM_REQ_CMP) {
3932                         warnx("Unexpected CAM status %#x", status);
3933                         if (arglist & CAM_ARG_VERBOSE)
3934                                 cam_error_print(device, ccb, CAM_ESF_ALL,
3935                                                 CAM_EPF_ALL, stderr);
3936                         error = 1;
3937                         goto scsiformat_bailout;
3938                 }
3939
3940         } while((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP);
3941
3942         if (quiet == 0)
3943                 fprintf(stdout, "\nFormat Complete\n");
3944
3945 scsiformat_bailout:
3946
3947         cam_freeccb(ccb);
3948
3949         return(error);
3950 }
3951
3952 static int
3953 scsireportluns(struct cam_device *device, int argc, char **argv,
3954                char *combinedopt, int retry_count, int timeout)
3955 {
3956         union ccb *ccb;
3957         int c, countonly, lunsonly;
3958         struct scsi_report_luns_data *lundata;
3959         int alloc_len;
3960         uint8_t report_type;
3961         uint32_t list_len, i, j;
3962         int retval;
3963
3964         retval = 0;
3965         lundata = NULL;
3966         report_type = RPL_REPORT_DEFAULT;
3967         ccb = cam_getccb(device);
3968
3969         if (ccb == NULL) {
3970                 warnx("%s: error allocating ccb", __func__);
3971                 return (1);
3972         }
3973
3974         bzero(&(&ccb->ccb_h)[1],
3975               sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
3976
3977         countonly = 0;
3978         lunsonly = 0;
3979
3980         while ((c = getopt(argc, argv, combinedopt)) != -1) {
3981                 switch (c) {
3982                 case 'c':
3983                         countonly++;
3984                         break;
3985                 case 'l':
3986                         lunsonly++;
3987                         break;
3988                 case 'r':
3989                         if (strcasecmp(optarg, "default") == 0)
3990                                 report_type = RPL_REPORT_DEFAULT;
3991                         else if (strcasecmp(optarg, "wellknown") == 0)
3992                                 report_type = RPL_REPORT_WELLKNOWN;
3993                         else if (strcasecmp(optarg, "all") == 0)
3994                                 report_type = RPL_REPORT_ALL;
3995                         else {
3996                                 warnx("%s: invalid report type \"%s\"",
3997                                       __func__, optarg);
3998                                 retval = 1;
3999                                 goto bailout;
4000                         }
4001                         break;
4002                 default:
4003                         break;
4004                 }
4005         }
4006
4007         if ((countonly != 0)
4008          && (lunsonly != 0)) {
4009                 warnx("%s: you can only specify one of -c or -l", __func__);
4010                 retval = 1;
4011                 goto bailout;
4012         }
4013         /*
4014          * According to SPC-4, the allocation length must be at least 16
4015          * bytes -- enough for the header and one LUN.
4016          */
4017         alloc_len = sizeof(*lundata) + 8;
4018
4019 retry:
4020
4021         lundata = malloc(alloc_len);
4022
4023         if (lundata == NULL) {
4024                 warn("%s: error mallocing %d bytes", __func__, alloc_len);
4025                 retval = 1;
4026                 goto bailout;
4027         }
4028
4029         scsi_report_luns(&ccb->csio,
4030                          /*retries*/ retry_count,
4031                          /*cbfcnp*/ NULL,
4032                          /*tag_action*/ MSG_SIMPLE_Q_TAG,
4033                          /*select_report*/ report_type,
4034                          /*rpl_buf*/ lundata,
4035                          /*alloc_len*/ alloc_len,
4036                          /*sense_len*/ SSD_FULL_SIZE,
4037                          /*timeout*/ timeout ? timeout : 5000);
4038
4039         /* Disable freezing the device queue */
4040         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
4041
4042         if (arglist & CAM_ARG_ERR_RECOVER)
4043                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
4044
4045         if (cam_send_ccb(device, ccb) < 0) {
4046                 warn("error sending REPORT LUNS command");
4047
4048                 if (arglist & CAM_ARG_VERBOSE)
4049                         cam_error_print(device, ccb, CAM_ESF_ALL,
4050                                         CAM_EPF_ALL, stderr);
4051
4052                 retval = 1;
4053                 goto bailout;
4054         }
4055
4056         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
4057                 cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
4058                 retval = 1;
4059                 goto bailout;
4060         }
4061
4062
4063         list_len = scsi_4btoul(lundata->length);
4064
4065         /*
4066          * If we need to list the LUNs, and our allocation
4067          * length was too short, reallocate and retry.
4068          */
4069         if ((countonly == 0)
4070          && (list_len > (alloc_len - sizeof(*lundata)))) {
4071                 alloc_len = list_len + sizeof(*lundata);
4072                 free(lundata);
4073                 goto retry;
4074         }
4075
4076         if (lunsonly == 0)
4077                 fprintf(stdout, "%u LUN%s found\n", list_len / 8,
4078                         ((list_len / 8) > 1) ? "s" : "");
4079
4080         if (countonly != 0)
4081                 goto bailout;
4082
4083         for (i = 0; i < (list_len / 8); i++) {
4084                 int no_more;
4085
4086                 no_more = 0;
4087                 for (j = 0; j < sizeof(lundata->luns[i].lundata); j += 2) {
4088                         if (j != 0)
4089                                 fprintf(stdout, ",");
4090                         switch (lundata->luns[i].lundata[j] &
4091                                 RPL_LUNDATA_ATYP_MASK) {
4092                         case RPL_LUNDATA_ATYP_PERIPH:
4093                                 if ((lundata->luns[i].lundata[j] &
4094                                     RPL_LUNDATA_PERIPH_BUS_MASK) != 0)
4095                                         fprintf(stdout, "%d:",
4096                                                 lundata->luns[i].lundata[j] &
4097                                                 RPL_LUNDATA_PERIPH_BUS_MASK);
4098                                 else if ((j == 0)
4099                                       && ((lundata->luns[i].lundata[j+2] &
4100                                           RPL_LUNDATA_PERIPH_BUS_MASK) == 0))
4101                                         no_more = 1;
4102
4103                                 fprintf(stdout, "%d",
4104                                         lundata->luns[i].lundata[j+1]);
4105                                 break;
4106                         case RPL_LUNDATA_ATYP_FLAT: {
4107                                 uint8_t tmplun[2];
4108                                 tmplun[0] = lundata->luns[i].lundata[j] &
4109                                         RPL_LUNDATA_FLAT_LUN_MASK;
4110                                 tmplun[1] = lundata->luns[i].lundata[j+1];
4111
4112                                 fprintf(stdout, "%d", scsi_2btoul(tmplun));
4113                                 no_more = 1;
4114                                 break;
4115                         }
4116                         case RPL_LUNDATA_ATYP_LUN:
4117                                 fprintf(stdout, "%d:%d:%d",
4118                                         (lundata->luns[i].lundata[j+1] &
4119                                         RPL_LUNDATA_LUN_BUS_MASK) >> 5,
4120                                         lundata->luns[i].lundata[j] &
4121                                         RPL_LUNDATA_LUN_TARG_MASK,
4122                                         lundata->luns[i].lundata[j+1] &
4123                                         RPL_LUNDATA_LUN_LUN_MASK);
4124                                 break;
4125                         case RPL_LUNDATA_ATYP_EXTLUN: {
4126                                 int field_len_code, eam_code;
4127
4128                                 eam_code = lundata->luns[i].lundata[j] &
4129                                         RPL_LUNDATA_EXT_EAM_MASK;
4130                                 field_len_code = (lundata->luns[i].lundata[j] &
4131                                         RPL_LUNDATA_EXT_LEN_MASK) >> 4;
4132
4133                                 if ((eam_code == RPL_LUNDATA_EXT_EAM_WK)
4134                                  && (field_len_code == 0x00)) {
4135                                         fprintf(stdout, "%d",
4136                                                 lundata->luns[i].lundata[j+1]);
4137                                 } else if ((eam_code ==
4138                                             RPL_LUNDATA_EXT_EAM_NOT_SPEC)
4139                                         && (field_len_code == 0x03)) {
4140                                         uint8_t tmp_lun[8];
4141
4142                                         /*
4143                                          * This format takes up all 8 bytes.
4144                                          * If we aren't starting at offset 0,
4145                                          * that's a bug.
4146                                          */
4147                                         if (j != 0) {
4148                                                 fprintf(stdout, "Invalid "
4149                                                         "offset %d for "
4150                                                         "Extended LUN not "
4151                                                         "specified format", j);
4152                                                 no_more = 1;
4153                                                 break;
4154                                         }
4155                                         bzero(tmp_lun, sizeof(tmp_lun));
4156                                         bcopy(&lundata->luns[i].lundata[j+1],
4157                                               &tmp_lun[1], sizeof(tmp_lun) - 1);
4158                                         fprintf(stdout, "%#jx",
4159                                                (intmax_t)scsi_8btou64(tmp_lun));
4160                                         no_more = 1;
4161                                 } else {
4162                                         fprintf(stderr, "Unknown Extended LUN"
4163                                                 "Address method %#x, length "
4164                                                 "code %#x", eam_code,
4165                                                 field_len_code);
4166                                         no_more = 1;
4167                                 }
4168                                 break;
4169                         }
4170                         default:
4171                                 fprintf(stderr, "Unknown LUN address method "
4172                                         "%#x\n", lundata->luns[i].lundata[0] &
4173                                         RPL_LUNDATA_ATYP_MASK);
4174                                 break;
4175                         }
4176                         /*
4177                          * For the flat addressing method, there are no
4178                          * other levels after it.
4179                          */
4180                         if (no_more != 0)
4181                                 break;
4182                 }
4183                 fprintf(stdout, "\n");
4184         }
4185
4186 bailout:
4187
4188         cam_freeccb(ccb);
4189
4190         free(lundata);
4191
4192         return (retval);
4193 }
4194
4195 static int
4196 scsireadcapacity(struct cam_device *device, int argc, char **argv,
4197                  char *combinedopt, int retry_count, int timeout)
4198 {
4199         union ccb *ccb;
4200         int blocksizeonly, humanize, numblocks, quiet, sizeonly, baseten;
4201         struct scsi_read_capacity_data rcap;
4202         struct scsi_read_capacity_data_long rcaplong;
4203         uint64_t maxsector;
4204         uint32_t block_len;
4205         int retval;
4206         int c;
4207
4208         blocksizeonly = 0;
4209         humanize = 0;
4210         numblocks = 0;
4211         quiet = 0;
4212         sizeonly = 0;
4213         baseten = 0;
4214         retval = 0;
4215
4216         ccb = cam_getccb(device);
4217
4218         if (ccb == NULL) {
4219                 warnx("%s: error allocating ccb", __func__);
4220                 return (1);
4221         }
4222
4223         bzero(&(&ccb->ccb_h)[1],
4224               sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
4225
4226         while ((c = getopt(argc, argv, combinedopt)) != -1) {
4227                 switch (c) {
4228                 case 'b':
4229                         blocksizeonly++;
4230                         break;
4231                 case 'h':
4232                         humanize++;
4233                         baseten = 0;
4234                         break;
4235                 case 'H':
4236                         humanize++;
4237                         baseten++;
4238                         break;
4239                 case 'N':
4240                         numblocks++;
4241                         break;
4242                 case 'q':
4243                         quiet++;
4244                         break;
4245                 case 's':
4246                         sizeonly++;
4247                         break;
4248                 default:
4249                         break;
4250                 }
4251         }
4252
4253         if ((blocksizeonly != 0)
4254          && (numblocks != 0)) {
4255                 warnx("%s: you can only specify one of -b or -N", __func__);
4256                 retval = 1;
4257                 goto bailout;
4258         }
4259
4260         if ((blocksizeonly != 0)
4261          && (sizeonly != 0)) {
4262                 warnx("%s: you can only specify one of -b or -s", __func__);
4263                 retval = 1;
4264                 goto bailout;
4265         }
4266
4267         if ((humanize != 0)
4268          && (quiet != 0)) {
4269                 warnx("%s: you can only specify one of -h/-H or -q", __func__);
4270                 retval = 1;
4271                 goto bailout;
4272         }
4273
4274         if ((humanize != 0)
4275          && (blocksizeonly != 0)) {
4276                 warnx("%s: you can only specify one of -h/-H or -b", __func__);
4277                 retval = 1;
4278                 goto bailout;
4279         }
4280
4281         scsi_read_capacity(&ccb->csio,
4282                            /*retries*/ retry_count,
4283                            /*cbfcnp*/ NULL,
4284                            /*tag_action*/ MSG_SIMPLE_Q_TAG,
4285                            &rcap,
4286                            SSD_FULL_SIZE,
4287                            /*timeout*/ timeout ? timeout : 5000);
4288
4289         /* Disable freezing the device queue */
4290         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
4291
4292         if (arglist & CAM_ARG_ERR_RECOVER)
4293                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
4294
4295         if (cam_send_ccb(device, ccb) < 0) {
4296                 warn("error sending READ CAPACITY command");
4297
4298                 if (arglist & CAM_ARG_VERBOSE)
4299                         cam_error_print(device, ccb, CAM_ESF_ALL,
4300                                         CAM_EPF_ALL, stderr);
4301
4302                 retval = 1;
4303                 goto bailout;
4304         }
4305
4306         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
4307                 cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
4308                 retval = 1;
4309                 goto bailout;
4310         }
4311
4312         maxsector = scsi_4btoul(rcap.addr);
4313         block_len = scsi_4btoul(rcap.length);
4314
4315         /*
4316          * A last block of 2^32-1 means that the true capacity is over 2TB,
4317          * and we need to issue the long READ CAPACITY to get the real
4318          * capacity.  Otherwise, we're all set.
4319          */
4320         if (maxsector != 0xffffffff)
4321                 goto do_print;
4322
4323         scsi_read_capacity_16(&ccb->csio,
4324                               /*retries*/ retry_count,
4325                               /*cbfcnp*/ NULL,
4326                               /*tag_action*/ MSG_SIMPLE_Q_TAG,
4327                               /*lba*/ 0,
4328                               /*reladdr*/ 0,
4329                               /*pmi*/ 0,
4330                               &rcaplong,
4331                               /*sense_len*/ SSD_FULL_SIZE,
4332                               /*timeout*/ timeout ? timeout : 5000);
4333
4334         /* Disable freezing the device queue */
4335         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
4336
4337         if (arglist & CAM_ARG_ERR_RECOVER)
4338                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
4339
4340         if (cam_send_ccb(device, ccb) < 0) {
4341                 warn("error sending READ CAPACITY (16) command");
4342
4343                 if (arglist & CAM_ARG_VERBOSE)
4344                         cam_error_print(device, ccb, CAM_ESF_ALL,
4345                                         CAM_EPF_ALL, stderr);
4346
4347                 retval = 1;
4348                 goto bailout;
4349         }
4350
4351         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
4352                 cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
4353                 retval = 1;
4354                 goto bailout;
4355         }
4356
4357         maxsector = scsi_8btou64(rcaplong.addr);
4358         block_len = scsi_4btoul(rcaplong.length);
4359
4360 do_print:
4361         if (blocksizeonly == 0) {
4362                 /*
4363                  * Humanize implies !quiet, and also implies numblocks.
4364                  */
4365                 if (humanize != 0) {
4366                         char tmpstr[6];
4367                         int64_t tmpbytes;
4368                         int ret;
4369
4370                         tmpbytes = (maxsector + 1) * block_len;
4371                         ret = humanize_number(tmpstr, sizeof(tmpstr),
4372                                               tmpbytes, "", HN_AUTOSCALE,
4373                                               HN_B | HN_DECIMAL |
4374                                               ((baseten != 0) ?
4375                                               HN_DIVISOR_1000 : 0));
4376                         if (ret == -1) {
4377                                 warnx("%s: humanize_number failed!", __func__);
4378                                 retval = 1;
4379                                 goto bailout;
4380                         }
4381                         fprintf(stdout, "Device Size: %s%s", tmpstr,
4382                                 (sizeonly == 0) ?  ", " : "\n");
4383                 } else if (numblocks != 0) {
4384                         fprintf(stdout, "%s%ju%s", (quiet == 0) ?
4385                                 "Blocks: " : "", (uintmax_t)maxsector + 1,
4386                                 (sizeonly == 0) ? ", " : "\n");
4387                 } else {
4388                         fprintf(stdout, "%s%ju%s", (quiet == 0) ?
4389                                 "Last Block: " : "", (uintmax_t)maxsector,
4390                                 (sizeonly == 0) ? ", " : "\n");
4391                 }
4392         }
4393         if (sizeonly == 0)
4394                 fprintf(stdout, "%s%u%s\n", (quiet == 0) ?
4395                         "Block Length: " : "", block_len, (quiet == 0) ?
4396                         " bytes" : "");
4397 bailout:
4398         cam_freeccb(ccb);
4399
4400         return (retval);
4401 }
4402
4403 static int
4404 smpcmd(struct cam_device *device, int argc, char **argv, char *combinedopt,
4405        int retry_count, int timeout)
4406 {
4407         int c, error;
4408         union ccb *ccb;
4409         uint8_t *smp_request = NULL, *smp_response = NULL;
4410         int request_size = 0, response_size = 0;
4411         int fd_request = 0, fd_response = 0;
4412         char *datastr = NULL;
4413         struct get_hook hook;
4414         int retval;
4415         int flags = 0;
4416
4417         /*
4418          * Note that at the moment we don't support sending SMP CCBs to
4419          * devices that aren't probed by CAM.
4420          */
4421         ccb = cam_getccb(device);
4422         if (ccb == NULL) {
4423                 warnx("%s: error allocating CCB", __func__);
4424                 return (1);
4425         }
4426
4427         bzero(&(&ccb->ccb_h)[1],
4428               sizeof(union ccb) - sizeof(struct ccb_hdr));
4429
4430         while ((c = getopt(argc, argv, combinedopt)) != -1) {
4431                 switch (c) {
4432                 case 'R':
4433                         arglist |= CAM_ARG_CMD_IN;
4434                         response_size = strtol(optarg, NULL, 0);
4435                         if (response_size <= 0) {
4436                                 warnx("invalid number of response bytes %d",
4437                                       response_size);
4438                                 error = 1;
4439                                 goto smpcmd_bailout;
4440                         }
4441                         hook.argc = argc - optind;
4442                         hook.argv = argv + optind;
4443                         hook.got = 0;
4444                         optind++;
4445                         datastr = cget(&hook, NULL);
4446                         /*
4447                          * If the user supplied "-" instead of a format, he
4448                          * wants the data to be written to stdout.
4449                          */
4450                         if ((datastr != NULL)
4451                          && (datastr[0] == '-'))
4452                                 fd_response = 1;
4453
4454                         smp_response = (u_int8_t *)malloc(response_size);
4455                         if (smp_response == NULL) {
4456                                 warn("can't malloc memory for SMP response");
4457                                 error = 1;
4458                                 goto smpcmd_bailout;
4459                         }
4460                         break;
4461                 case 'r':
4462                         arglist |= CAM_ARG_CMD_OUT;
4463                         request_size = strtol(optarg, NULL, 0);
4464                         if (request_size <= 0) {
4465                                 warnx("invalid number of request bytes %d",
4466                                       request_size);
4467                                 error = 1;
4468                                 goto smpcmd_bailout;
4469                         }
4470                         hook.argc = argc - optind;
4471                         hook.argv = argv + optind;
4472                         hook.got = 0;
4473                         datastr = cget(&hook, NULL);
4474                         smp_request = (u_int8_t *)malloc(request_size);
4475                         if (smp_request == NULL) {
4476                                 warn("can't malloc memory for SMP request");
4477                                 error = 1;
4478                                 goto smpcmd_bailout;
4479                         }
4480                         bzero(smp_request, request_size);
4481                         /*
4482                          * If the user supplied "-" instead of a format, he
4483                          * wants the data to be read from stdin.
4484                          */
4485                         if ((datastr != NULL)
4486                          && (datastr[0] == '-'))
4487                                 fd_request = 1;
4488                         else
4489                                 buff_encode_visit(smp_request, request_size,
4490                                                   datastr,
4491                                                   iget, &hook);
4492                         optind += hook.got;
4493                         break;
4494                 default:
4495                         break;
4496                 }
4497         }
4498
4499         /*
4500          * If fd_data is set, and we're writing to the device, we need to
4501          * read the data the user wants written from stdin.
4502          */
4503         if ((fd_request == 1) && (arglist & CAM_ARG_CMD_OUT)) {
4504                 ssize_t amt_read;
4505                 int amt_to_read = request_size;
4506                 u_int8_t *buf_ptr = smp_request;
4507
4508                 for (amt_read = 0; amt_to_read > 0;
4509                      amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) {
4510                         if (amt_read == -1) {
4511                                 warn("error reading data from stdin");
4512                                 error = 1;
4513                                 goto smpcmd_bailout;
4514                         }
4515                         amt_to_read -= amt_read;
4516                         buf_ptr += amt_read;
4517                 }
4518         }
4519
4520         if (((arglist & CAM_ARG_CMD_IN) == 0)
4521          || ((arglist & CAM_ARG_CMD_OUT) == 0)) {
4522                 warnx("%s: need both the request (-r) and response (-R) "
4523                       "arguments", __func__);
4524                 error = 1;
4525                 goto smpcmd_bailout;
4526         }
4527
4528         flags |= CAM_DEV_QFRZDIS;
4529
4530         cam_fill_smpio(&ccb->smpio,
4531                        /*retries*/ retry_count,
4532                        /*cbfcnp*/ NULL,
4533                        /*flags*/ flags,
4534                        /*smp_request*/ smp_request,
4535                        /*smp_request_len*/ request_size,
4536                        /*smp_response*/ smp_response,
4537                        /*smp_response_len*/ response_size,
4538                        /*timeout*/ timeout ? timeout : 5000);
4539
4540         ccb->smpio.flags = SMP_FLAG_NONE;
4541
4542         if (((retval = cam_send_ccb(device, ccb)) < 0)
4543          || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
4544                 const char warnstr[] = "error sending command";
4545
4546                 if (retval < 0)
4547                         warn(warnstr);
4548                 else
4549                         warnx(warnstr);
4550
4551                 if (arglist & CAM_ARG_VERBOSE) {
4552                         cam_error_print(device, ccb, CAM_ESF_ALL,
4553                                         CAM_EPF_ALL, stderr);
4554                 }
4555         }
4556
4557         if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
4558          && (response_size > 0)) {
4559                 if (fd_response == 0) {
4560                         buff_decode_visit(smp_response, response_size,
4561                                           datastr, arg_put, NULL);
4562                         fprintf(stdout, "\n");
4563                 } else {
4564                         ssize_t amt_written;
4565                         int amt_to_write = response_size;
4566                         u_int8_t *buf_ptr = smp_response;
4567
4568                         for (amt_written = 0; (amt_to_write > 0) &&
4569                              (amt_written = write(STDOUT_FILENO, buf_ptr,
4570                                                   amt_to_write)) > 0;){
4571                                 amt_to_write -= amt_written;
4572                                 buf_ptr += amt_written;
4573                         }
4574                         if (amt_written == -1) {
4575                                 warn("error writing data to stdout");
4576                                 error = 1;
4577                                 goto smpcmd_bailout;
4578                         } else if ((amt_written == 0)
4579                                 && (amt_to_write > 0)) {
4580                                 warnx("only wrote %u bytes out of %u",
4581                                       response_size - amt_to_write, 
4582                                       response_size);
4583                         }
4584                 }
4585         }
4586 smpcmd_bailout:
4587         if (ccb != NULL)
4588                 cam_freeccb(ccb);
4589
4590         if (smp_request != NULL)
4591                 free(smp_request);
4592
4593         if (smp_response != NULL)
4594                 free(smp_response);
4595
4596         return (error);
4597 }
4598
4599 static int
4600 smpreportgeneral(struct cam_device *device, int argc, char **argv,
4601                  char *combinedopt, int retry_count, int timeout)
4602 {
4603         union ccb *ccb;
4604         struct smp_report_general_request *request = NULL;
4605         struct smp_report_general_response *response = NULL;
4606         struct sbuf *sb = NULL;
4607         int error = 0;
4608         int c, long_response = 0;
4609         int retval;
4610
4611         /*
4612          * Note that at the moment we don't support sending SMP CCBs to
4613          * devices that aren't probed by CAM.
4614          */
4615         ccb = cam_getccb(device);
4616         if (ccb == NULL) {
4617                 warnx("%s: error allocating CCB", __func__);
4618                 return (1);
4619         }
4620
4621         bzero(&(&ccb->ccb_h)[1],
4622               sizeof(union ccb) - sizeof(struct ccb_hdr));
4623
4624         while ((c = getopt(argc, argv, combinedopt)) != -1) {
4625                 switch (c) {
4626                 case 'l':
4627                         long_response = 1;
4628                         break;
4629                 default:
4630                         break;
4631                 }
4632         }
4633         request = malloc(sizeof(*request));
4634         if (request == NULL) {
4635                 warn("%s: unable to allocate %zd bytes", __func__,
4636                      sizeof(*request));
4637                 error = 1;
4638                 goto bailout;
4639         }
4640
4641         response = malloc(sizeof(*response));
4642         if (response == NULL) {
4643                 warn("%s: unable to allocate %zd bytes", __func__,
4644                      sizeof(*response));
4645                 error = 1;
4646                 goto bailout;
4647         }
4648
4649 try_long:
4650         smp_report_general(&ccb->smpio,
4651                            retry_count,
4652                            /*cbfcnp*/ NULL,
4653                            request,
4654                            /*request_len*/ sizeof(*request),
4655                            (uint8_t *)response,
4656                            /*response_len*/ sizeof(*response),
4657                            /*long_response*/ long_response,
4658                            timeout);
4659
4660         if (((retval = cam_send_ccb(device, ccb)) < 0)
4661          || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
4662                 const char warnstr[] = "error sending command";
4663
4664                 if (retval < 0)
4665                         warn(warnstr);
4666                 else
4667                         warnx(warnstr);
4668
4669                 if (arglist & CAM_ARG_VERBOSE) {
4670                         cam_error_print(device, ccb, CAM_ESF_ALL,
4671                                         CAM_EPF_ALL, stderr);
4672                 }
4673                 error = 1;
4674                 goto bailout;
4675         }
4676
4677         /*
4678          * If the device supports the long response bit, try again and see
4679          * if we can get all of the data.
4680          */
4681         if ((response->long_response & SMP_RG_LONG_RESPONSE)
4682          && (long_response == 0)) {
4683                 ccb->ccb_h.status = CAM_REQ_INPROG;
4684                 bzero(&(&ccb->ccb_h)[1],
4685                       sizeof(union ccb) - sizeof(struct ccb_hdr));
4686                 long_response = 1;
4687                 goto try_long;
4688         }
4689
4690         /*
4691          * XXX KDM detect and decode SMP errors here.
4692          */
4693         sb = sbuf_new_auto();
4694         if (sb == NULL) {
4695                 warnx("%s: error allocating sbuf", __func__);
4696                 goto bailout;
4697         }
4698
4699         smp_report_general_sbuf(response, sizeof(*response), sb);
4700
4701         sbuf_finish(sb);
4702
4703         printf("%s", sbuf_data(sb));
4704
4705 bailout:
4706         if (ccb != NULL)
4707                 cam_freeccb(ccb);
4708
4709         if (request != NULL)
4710                 free(request);
4711
4712         if (response != NULL)
4713                 free(response);
4714
4715         if (sb != NULL)
4716                 sbuf_delete(sb);
4717
4718         return (error);
4719 }
4720
4721 struct camcontrol_opts phy_ops[] = {
4722         {"nop", SMP_PC_PHY_OP_NOP, CAM_ARG_NONE, NULL},
4723         {"linkreset", SMP_PC_PHY_OP_LINK_RESET, CAM_ARG_NONE, NULL},
4724         {"hardreset", SMP_PC_PHY_OP_HARD_RESET, CAM_ARG_NONE, NULL},
4725         {"disable", SMP_PC_PHY_OP_DISABLE, CAM_ARG_NONE, NULL},
4726         {"clearerrlog", SMP_PC_PHY_OP_CLEAR_ERR_LOG, CAM_ARG_NONE, NULL},
4727         {"clearaffiliation", SMP_PC_PHY_OP_CLEAR_AFFILIATON, CAM_ARG_NONE,NULL},
4728         {"sataportsel", SMP_PC_PHY_OP_TRANS_SATA_PSS, CAM_ARG_NONE, NULL},
4729         {"clearitnl", SMP_PC_PHY_OP_CLEAR_STP_ITN_LS, CAM_ARG_NONE, NULL},
4730         {"setdevname", SMP_PC_PHY_OP_SET_ATT_DEV_NAME, CAM_ARG_NONE, NULL},
4731         {NULL, 0, 0, NULL}
4732 };
4733
4734 static int
4735 smpphycontrol(struct cam_device *device, int argc, char **argv,
4736               char *combinedopt, int retry_count, int timeout)
4737 {
4738         union ccb *ccb;
4739         struct smp_phy_control_request *request = NULL;
4740         struct smp_phy_control_response *response = NULL;
4741         int long_response = 0;
4742         int retval = 0;
4743         int phy = -1;
4744         uint32_t phy_operation = SMP_PC_PHY_OP_NOP;
4745         int phy_op_set = 0;
4746         uint64_t attached_dev_name = 0;
4747         int dev_name_set = 0;
4748         uint32_t min_plr = 0, max_plr = 0;
4749         uint32_t pp_timeout_val = 0;
4750         int slumber_partial = 0;
4751         int set_pp_timeout_val = 0;
4752         int c;
4753
4754         /*
4755          * Note that at the moment we don't support sending SMP CCBs to
4756          * devices that aren't probed by CAM.
4757          */
4758         ccb = cam_getccb(device);
4759         if (ccb == NULL) {
4760                 warnx("%s: error allocating CCB", __func__);
4761                 return (1);
4762         }
4763
4764         bzero(&(&ccb->ccb_h)[1],
4765               sizeof(union ccb) - sizeof(struct ccb_hdr));
4766
4767         while ((c = getopt(argc, argv, combinedopt)) != -1) {
4768                 switch (c) {
4769                 case 'a':
4770                 case 'A':
4771                 case 's':
4772                 case 'S': {
4773                         int enable = -1;
4774
4775                         if (strcasecmp(optarg, "enable") == 0)
4776                                 enable = 1;
4777                         else if (strcasecmp(optarg, "disable") == 0)
4778                                 enable = 2;
4779                         else {
4780                                 warnx("%s: Invalid argument %s", __func__,
4781                                       optarg);
4782                                 retval = 1;
4783                                 goto bailout;
4784                         }
4785                         switch (c) {
4786                         case 's':
4787                                 slumber_partial |= enable <<
4788                                                    SMP_PC_SAS_SLUMBER_SHIFT;
4789                                 break;
4790                         case 'S':
4791                                 slumber_partial |= enable <<
4792                                                    SMP_PC_SAS_PARTIAL_SHIFT;
4793                                 break;
4794                         case 'a':
4795                                 slumber_partial |= enable <<
4796                                                    SMP_PC_SATA_SLUMBER_SHIFT;
4797                                 break;
4798                         case 'A':
4799                                 slumber_partial |= enable <<
4800                                                    SMP_PC_SATA_PARTIAL_SHIFT;
4801                                 break;
4802                         default:
4803                                 warnx("%s: programmer error", __func__);
4804                                 retval = 1;
4805                                 goto bailout;
4806                                 break; /*NOTREACHED*/
4807                         }
4808                         break;
4809                 }
4810                 case 'd':
4811                         attached_dev_name = (uintmax_t)strtoumax(optarg,
4812                                                                  NULL,0);
4813                         dev_name_set = 1;
4814                         break;
4815                 case 'l':
4816                         long_response = 1;
4817                         break;
4818                 case 'm':
4819                         /*
4820                          * We don't do extensive checking here, so this
4821                          * will continue to work when new speeds come out.
4822                          */
4823                         min_plr = strtoul(optarg, NULL, 0);
4824                         if ((min_plr == 0)
4825                          || (min_plr > 0xf)) {
4826                                 warnx("%s: invalid link rate %x",
4827                                       __func__, min_plr);
4828                                 retval = 1;
4829                                 goto bailout;
4830                         }
4831                         break;
4832                 case 'M':
4833                         /*
4834                          * We don't do extensive checking here, so this
4835                          * will continue to work when new speeds come out.
4836                          */
4837                         max_plr = strtoul(optarg, NULL, 0);
4838                         if ((max_plr == 0)
4839                          || (max_plr > 0xf)) {
4840                                 warnx("%s: invalid link rate %x",
4841                                       __func__, max_plr);
4842                                 retval = 1;
4843                                 goto bailout;
4844                         }
4845                         break;
4846                 case 'o': {
4847                         camcontrol_optret optreturn;
4848                         cam_argmask argnums;
4849                         const char *subopt;
4850
4851                         if (phy_op_set != 0) {
4852                                 warnx("%s: only one phy operation argument "
4853                                       "(-o) allowed", __func__);
4854                                 retval = 1;
4855                                 goto bailout;
4856                         }
4857
4858                         phy_op_set = 1;
4859
4860                         /*
4861                          * Allow the user to specify the phy operation
4862                          * numerically, as well as with a name.  This will
4863                          * future-proof it a bit, so options that are added
4864                          * in future specs can be used.
4865                          */
4866                         if (isdigit(optarg[0])) {
4867                                 phy_operation = strtoul(optarg, NULL, 0);
4868                                 if ((phy_operation == 0)
4869                                  || (phy_operation > 0xff)) {
4870                                         warnx("%s: invalid phy operation %#x",
4871                                               __func__, phy_operation);
4872                                         retval = 1;
4873                                         goto bailout;
4874                                 }
4875                                 break;
4876                         }
4877                         optreturn = getoption(phy_ops, optarg, &phy_operation,
4878                                               &argnums, &subopt);
4879
4880                         if (optreturn == CC_OR_AMBIGUOUS) {
4881                                 warnx("%s: ambiguous option %s", __func__,
4882                                       optarg);
4883                                 usage(0);
4884                                 retval = 1;
4885                                 goto bailout;
4886                         } else if (optreturn == CC_OR_NOT_FOUND) {
4887                                 warnx("%s: option %s not found", __func__,
4888                                       optarg);
4889                                 usage(0);
4890                                 retval = 1;
4891                                 goto bailout;
4892                         }
4893                         break;
4894                 }
4895                 case 'p':
4896                         phy = atoi(optarg);
4897                         break;
4898                 case 'T':
4899                         pp_timeout_val = strtoul(optarg, NULL, 0);
4900                         if (pp_timeout_val > 15) {
4901                                 warnx("%s: invalid partial pathway timeout "
4902                                       "value %u, need a value less than 16",
4903                                       __func__, pp_timeout_val);
4904                                 retval = 1;
4905                                 goto bailout;
4906                         }
4907                         set_pp_timeout_val = 1;
4908                         break;
4909                 default:
4910                         break;
4911                 }
4912         }
4913
4914         if (phy == -1) {
4915                 warnx("%s: a PHY (-p phy) argument is required",__func__);
4916                 retval = 1;
4917                 goto bailout;
4918         }
4919
4920         if (((dev_name_set != 0)
4921           && (phy_operation != SMP_PC_PHY_OP_SET_ATT_DEV_NAME))
4922          || ((phy_operation == SMP_PC_PHY_OP_SET_ATT_DEV_NAME)
4923           && (dev_name_set == 0))) {
4924                 warnx("%s: -d name and -o setdevname arguments both "
4925                       "required to set device name", __func__);
4926                 retval = 1;
4927                 goto bailout;
4928         }
4929
4930         request = malloc(sizeof(*request));
4931         if (request == NULL) {
4932                 warn("%s: unable to allocate %zd bytes", __func__,
4933                      sizeof(*request));
4934                 retval = 1;
4935                 goto bailout;
4936         }
4937
4938         response = malloc(sizeof(*response));
4939         if (response == NULL) {
4940                 warn("%s: unable to allocate %zd bytes", __func__,
4941                      sizeof(*request));
4942                 retval = 1;
4943                 goto bailout;
4944         }
4945
4946         smp_phy_control(&ccb->smpio,
4947                         retry_count,
4948                         /*cbfcnp*/ NULL,
4949                         request,
4950                         sizeof(*request),
4951                         (uint8_t *)response,
4952                         sizeof(*response),
4953                         long_response,
4954                         /*expected_exp_change_count*/ 0,
4955                         phy,
4956                         phy_operation,
4957                         (set_pp_timeout_val != 0) ? 1 : 0,
4958                         attached_dev_name,
4959                         min_plr,
4960                         max_plr,
4961                         slumber_partial,
4962                         pp_timeout_val,
4963                         timeout);
4964
4965         if (((retval = cam_send_ccb(device, ccb)) < 0)
4966          || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
4967                 const char warnstr[] = "error sending command";
4968
4969                 if (retval < 0)
4970                         warn(warnstr);
4971                 else
4972                         warnx(warnstr);
4973
4974                 if (arglist & CAM_ARG_VERBOSE) {
4975                         /*
4976                          * Use CAM_EPF_NORMAL so we only get one line of
4977                          * SMP command decoding.
4978                          */
4979                         cam_error_print(device, ccb, CAM_ESF_ALL,
4980                                         CAM_EPF_NORMAL, stderr);
4981                 }
4982                 retval = 1;
4983                 goto bailout;
4984         }
4985
4986         /* XXX KDM print out something here for success? */
4987 bailout:
4988         if (ccb != NULL)
4989                 cam_freeccb(ccb);
4990
4991         if (request != NULL)
4992                 free(request);
4993
4994         if (response != NULL)
4995                 free(response);
4996
4997         return (retval);
4998 }
4999
5000 static int
5001 smpmaninfo(struct cam_device *device, int argc, char **argv,
5002            char *combinedopt, int retry_count, int timeout)
5003 {
5004         union ccb *ccb;
5005         struct smp_report_manuf_info_request request;
5006         struct smp_report_manuf_info_response response;
5007         struct sbuf *sb = NULL;
5008         int long_response = 0;
5009         int retval = 0;
5010         int c;
5011
5012         /*
5013          * Note that at the moment we don't support sending SMP CCBs to
5014          * devices that aren't probed by CAM.
5015          */
5016         ccb = cam_getccb(device);
5017         if (ccb == NULL) {
5018                 warnx("%s: error allocating CCB", __func__);
5019                 return (1);
5020         }
5021
5022         bzero(&(&ccb->ccb_h)[1],
5023               sizeof(union ccb) - sizeof(struct ccb_hdr));
5024
5025         while ((c = getopt(argc, argv, combinedopt)) != -1) {
5026                 switch (c) {
5027                 case 'l':
5028                         long_response = 1;
5029                         break;
5030                 default:
5031                         break;
5032                 }
5033         }
5034         bzero(&request, sizeof(request));
5035         bzero(&response, sizeof(response));
5036
5037         smp_report_manuf_info(&ccb->smpio,
5038                               retry_count,
5039                               /*cbfcnp*/ NULL,
5040                               &request,
5041                               sizeof(request),
5042                               (uint8_t *)&response,
5043                               sizeof(response),
5044                               long_response,
5045                               timeout);
5046
5047         if (((retval = cam_send_ccb(device, ccb)) < 0)
5048          || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
5049                 const char warnstr[] = "error sending command";
5050
5051                 if (retval < 0)
5052                         warn(warnstr);
5053                 else
5054                         warnx(warnstr);
5055
5056                 if (arglist & CAM_ARG_VERBOSE) {
5057                         cam_error_print(device, ccb, CAM_ESF_ALL,
5058                                         CAM_EPF_ALL, stderr);
5059                 }
5060                 retval = 1;
5061                 goto bailout;
5062         }
5063
5064         sb = sbuf_new_auto();
5065         if (sb == NULL) {
5066                 warnx("%s: error allocating sbuf", __func__);
5067                 goto bailout;
5068         }
5069
5070         smp_report_manuf_info_sbuf(&response, sizeof(response), sb);
5071
5072         sbuf_finish(sb);
5073
5074         printf("%s", sbuf_data(sb));
5075
5076 bailout:
5077
5078         if (ccb != NULL)
5079                 cam_freeccb(ccb);
5080
5081         if (sb != NULL)
5082                 sbuf_delete(sb);
5083
5084         return (retval);
5085 }
5086
5087 static int
5088 getdevid(struct cam_devitem *item)
5089 {
5090         int retval = 0;
5091         union ccb *ccb = NULL;
5092
5093         struct cam_device *dev;
5094
5095         dev = cam_open_btl(item->dev_match.path_id,
5096                            item->dev_match.target_id,
5097                            item->dev_match.target_lun, O_RDWR, NULL);
5098
5099         if (dev == NULL) {
5100                 warnx("%s", cam_errbuf);
5101                 retval = 1;
5102                 goto bailout;
5103         }
5104
5105         item->device_id_len = 0;
5106
5107         ccb = cam_getccb(dev);
5108         if (ccb == NULL) {
5109                 warnx("%s: error allocating CCB", __func__);
5110                 retval = 1;
5111                 goto bailout;
5112         }
5113
5114         bzero(&(&ccb->ccb_h)[1],
5115               sizeof(union ccb) - sizeof(struct ccb_hdr));
5116
5117         /*
5118          * On the first try, we just probe for the size of the data, and
5119          * then allocate that much memory and try again.
5120          */
5121 retry:
5122         ccb->ccb_h.func_code = XPT_DEV_ADVINFO;
5123         ccb->ccb_h.flags = CAM_DIR_IN;
5124         ccb->cdai.flags = 0;
5125         ccb->cdai.buftype = CDAI_TYPE_SCSI_DEVID;
5126         ccb->cdai.bufsiz = item->device_id_len;
5127         if (item->device_id_len != 0)
5128                 ccb->cdai.buf = (uint8_t *)item->device_id;
5129
5130         if (cam_send_ccb(dev, ccb) < 0) {
5131                 warn("%s: error sending XPT_GDEV_ADVINFO CCB", __func__);
5132                 retval = 1;
5133                 goto bailout;
5134         }
5135
5136         if (ccb->ccb_h.status != CAM_REQ_CMP) {
5137                 warnx("%s: CAM status %#x", __func__, ccb->ccb_h.status);
5138                 retval = 1;
5139                 goto bailout;
5140         }
5141
5142         if (item->device_id_len == 0) {
5143                 /*
5144                  * This is our first time through.  Allocate the buffer,
5145                  * and then go back to get the data.
5146                  */
5147                 if (ccb->cdai.provsiz == 0) {
5148                         warnx("%s: invalid .provsiz field returned with "
5149                              "XPT_GDEV_ADVINFO CCB", __func__);
5150                         retval = 1;
5151                         goto bailout;
5152                 }
5153                 item->device_id_len = ccb->cdai.provsiz;
5154                 item->device_id = malloc(item->device_id_len);
5155                 if (item->device_id == NULL) {
5156                         warn("%s: unable to allocate %d bytes", __func__,
5157                              item->device_id_len);
5158                         retval = 1;
5159                         goto bailout;
5160                 }
5161                 ccb->ccb_h.status = CAM_REQ_INPROG;
5162                 goto retry;
5163         }
5164
5165 bailout:
5166         if (dev != NULL)
5167                 cam_close_device(dev);
5168
5169         if (ccb != NULL)
5170                 cam_freeccb(ccb);
5171
5172         return (retval);
5173 }
5174
5175 /*
5176  * XXX KDM merge this code with getdevtree()?
5177  */
5178 static int
5179 buildbusdevlist(struct cam_devlist *devlist)
5180 {
5181         union ccb ccb;
5182         int bufsize, fd = -1;
5183         struct dev_match_pattern *patterns;
5184         struct cam_devitem *item = NULL;
5185         int skip_device = 0;
5186         int retval = 0;
5187
5188         if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
5189                 warn("couldn't open %s", XPT_DEVICE);
5190                 return(1);
5191         }
5192
5193         bzero(&ccb, sizeof(union ccb));
5194
5195         ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
5196         ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
5197         ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
5198
5199         ccb.ccb_h.func_code = XPT_DEV_MATCH;
5200         bufsize = sizeof(struct dev_match_result) * 100;
5201         ccb.cdm.match_buf_len = bufsize;
5202         ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
5203         if (ccb.cdm.matches == NULL) {
5204                 warnx("can't malloc memory for matches");
5205                 close(fd);
5206                 return(1);
5207         }
5208         ccb.cdm.num_matches = 0;
5209         ccb.cdm.num_patterns = 2;
5210         ccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern) *
5211                 ccb.cdm.num_patterns;
5212
5213         patterns = (struct dev_match_pattern *)malloc(ccb.cdm.pattern_buf_len);
5214         if (patterns == NULL) {
5215                 warnx("can't malloc memory for patterns");
5216                 retval = 1;
5217                 goto bailout;
5218         }
5219
5220         ccb.cdm.patterns = patterns;
5221         bzero(patterns, ccb.cdm.pattern_buf_len);
5222
5223         patterns[0].type = DEV_MATCH_DEVICE;
5224         patterns[0].pattern.device_pattern.flags = DEV_MATCH_PATH;
5225         patterns[0].pattern.device_pattern.path_id = devlist->path_id;
5226         patterns[1].type = DEV_MATCH_PERIPH;
5227         patterns[1].pattern.periph_pattern.flags = PERIPH_MATCH_PATH;
5228         patterns[1].pattern.periph_pattern.path_id = devlist->path_id;
5229
5230         /*
5231          * We do the ioctl multiple times if necessary, in case there are
5232          * more than 100 nodes in the EDT.
5233          */
5234         do {
5235                 unsigned int i;
5236
5237                 if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
5238                         warn("error sending CAMIOCOMMAND ioctl");
5239                         retval = 1;
5240                         goto bailout;
5241                 }
5242
5243                 if ((ccb.ccb_h.status != CAM_REQ_CMP)
5244                  || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
5245                     && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
5246                         warnx("got CAM error %#x, CDM error %d\n",
5247                               ccb.ccb_h.status, ccb.cdm.status);
5248                         retval = 1;
5249                         goto bailout;
5250                 }
5251
5252                 for (i = 0; i < ccb.cdm.num_matches; i++) {
5253                         switch (ccb.cdm.matches[i].type) {
5254                         case DEV_MATCH_DEVICE: {
5255                                 struct device_match_result *dev_result;
5256
5257                                 dev_result = 
5258                                      &ccb.cdm.matches[i].result.device_result;
5259
5260                                 if (dev_result->flags &
5261                                     DEV_RESULT_UNCONFIGURED) {
5262                                         skip_device = 1;
5263                                         break;
5264                                 } else
5265                                         skip_device = 0;
5266
5267                                 item = malloc(sizeof(*item));
5268                                 if (item == NULL) {
5269                                         warn("%s: unable to allocate %zd bytes",
5270                                              __func__, sizeof(*item));
5271                                         retval = 1;
5272                                         goto bailout;
5273                                 }
5274                                 bzero(item, sizeof(*item));
5275                                 bcopy(dev_result, &item->dev_match,
5276                                       sizeof(*dev_result));
5277                                 STAILQ_INSERT_TAIL(&devlist->dev_queue, item,
5278                                                    links);
5279
5280                                 if (getdevid(item) != 0) {
5281                                         retval = 1;
5282                                         goto bailout;
5283                                 }
5284                                 break;
5285                         }
5286                         case DEV_MATCH_PERIPH: {
5287                                 struct periph_match_result *periph_result;
5288
5289                                 periph_result =
5290                                       &ccb.cdm.matches[i].result.periph_result;
5291
5292                                 if (skip_device != 0)
5293                                         break;
5294                                 item->num_periphs++;
5295                                 item->periph_matches = realloc(
5296                                         item->periph_matches,
5297                                         item->num_periphs *
5298                                         sizeof(struct periph_match_result));
5299                                 if (item->periph_matches == NULL) {
5300                                         warn("%s: error allocating periph "
5301                                              "list", __func__);
5302                                         retval = 1;
5303                                         goto bailout;
5304                                 }
5305                                 bcopy(periph_result, &item->periph_matches[
5306                                       item->num_periphs - 1],
5307                                       sizeof(*periph_result));
5308                                 break;
5309                         }
5310                         default:
5311                                 fprintf(stderr, "%s: unexpected match "
5312                                         "type %d\n", __func__,
5313                                         ccb.cdm.matches[i].type);
5314                                 retval = 1;
5315                                 goto bailout;
5316                                 break; /*NOTREACHED*/
5317                         }
5318                 }
5319         } while ((ccb.ccb_h.status == CAM_REQ_CMP)
5320                 && (ccb.cdm.status == CAM_DEV_MATCH_MORE));
5321 bailout:
5322
5323         if (fd != -1)
5324                 close(fd);
5325
5326         free(patterns);
5327
5328         free(ccb.cdm.matches);
5329
5330         if (retval != 0)
5331                 freebusdevlist(devlist);
5332
5333         return (retval);
5334 }
5335
5336 static void
5337 freebusdevlist(struct cam_devlist *devlist)
5338 {
5339         struct cam_devitem *item, *item2;
5340
5341         STAILQ_FOREACH_SAFE(item, &devlist->dev_queue, links, item2) {
5342                 STAILQ_REMOVE(&devlist->dev_queue, item, cam_devitem,
5343                               links);
5344                 free(item->device_id);
5345                 free(item->periph_matches);
5346                 free(item);
5347         }
5348 }
5349
5350 static struct cam_devitem *
5351 findsasdevice(struct cam_devlist *devlist, uint64_t sasaddr)
5352 {
5353         struct cam_devitem *item;
5354
5355         STAILQ_FOREACH(item, &devlist->dev_queue, links) {
5356                 uint8_t *item_addr;
5357
5358                 /*
5359                  * XXX KDM look for LUN IDs as well?
5360                  */
5361                 item_addr = scsi_get_devid(item->device_id,
5362                                            item->device_id_len,
5363                                            scsi_devid_is_sas_target);
5364                 if (item_addr == NULL)
5365                         continue;
5366
5367                 if (scsi_8btou64(item_addr) == sasaddr)
5368                         return (item);
5369         }
5370
5371         return (NULL);
5372 }
5373
5374 static int
5375 smpphylist(struct cam_device *device, int argc, char **argv,
5376            char *combinedopt, int retry_count, int timeout)
5377 {
5378         struct smp_report_general_request *rgrequest = NULL;
5379         struct smp_report_general_response *rgresponse = NULL;
5380         struct smp_discover_request *disrequest = NULL;
5381         struct smp_discover_response *disresponse = NULL;
5382         struct cam_devlist devlist;
5383         union ccb *ccb;
5384         int long_response = 0;
5385         int num_phys = 0;
5386         int quiet = 0;
5387         int retval;
5388         int i, c;
5389
5390         /*
5391          * Note that at the moment we don't support sending SMP CCBs to
5392          * devices that aren't probed by CAM.
5393          */
5394         ccb = cam_getccb(device);
5395         if (ccb == NULL) {
5396                 warnx("%s: error allocating CCB", __func__);
5397                 return (1);
5398         }
5399
5400         bzero(&(&ccb->ccb_h)[1],
5401               sizeof(union ccb) - sizeof(struct ccb_hdr));
5402
5403         rgrequest = malloc(sizeof(*rgrequest));
5404         if (rgrequest == NULL) {
5405                 warn("%s: unable to allocate %zd bytes", __func__,
5406                      sizeof(*rgrequest));
5407                 retval = 1;
5408                 goto bailout;
5409         }
5410
5411         rgresponse = malloc(sizeof(*rgresponse));
5412         if (rgresponse == NULL) {
5413                 warn("%s: unable to allocate %zd bytes", __func__,
5414                      sizeof(*rgresponse));
5415                 retval = 1;
5416                 goto bailout;
5417         }
5418
5419         while ((c = getopt(argc, argv, combinedopt)) != -1) {
5420                 switch (c) {
5421                 case 'l':
5422                         long_response = 1;
5423                         break;
5424                 case 'q':
5425                         quiet = 1;
5426                         break;
5427                 default:
5428                         break;
5429                 }
5430         }
5431
5432         smp_report_general(&ccb->smpio,
5433                            retry_count,
5434                            /*cbfcnp*/ NULL,
5435                            rgrequest,
5436                            /*request_len*/ sizeof(*rgrequest),
5437                            (uint8_t *)rgresponse,
5438                            /*response_len*/ sizeof(*rgresponse),
5439                            /*long_response*/ long_response,
5440                            timeout);
5441
5442         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
5443
5444         if (((retval = cam_send_ccb(device, ccb)) < 0)
5445          || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
5446                 const char warnstr[] = "error sending command";
5447
5448                 if (retval < 0)
5449                         warn(warnstr);
5450                 else
5451                         warnx(warnstr);
5452
5453                 if (arglist & CAM_ARG_VERBOSE) {
5454                         cam_error_print(device, ccb, CAM_ESF_ALL,
5455                                         CAM_EPF_ALL, stderr);
5456                 }
5457                 retval = 1;
5458                 goto bailout;
5459         }
5460
5461         num_phys = rgresponse->num_phys;
5462
5463         if (num_phys == 0) {
5464                 if (quiet == 0)
5465                         fprintf(stdout, "%s: No Phys reported\n", __func__);
5466                 retval = 1;
5467                 goto bailout;
5468         }
5469
5470         STAILQ_INIT(&devlist.dev_queue);
5471         devlist.path_id = device->path_id;
5472
5473         retval = buildbusdevlist(&devlist);
5474         if (retval != 0)
5475                 goto bailout;
5476
5477         if (quiet == 0) {
5478                 fprintf(stdout, "%d PHYs:\n", num_phys);
5479                 fprintf(stdout, "PHY  Attached SAS Address\n");
5480         }
5481
5482         disrequest = malloc(sizeof(*disrequest));
5483         if (disrequest == NULL) {
5484                 warn("%s: unable to allocate %zd bytes", __func__,
5485                      sizeof(*disrequest));
5486                 retval = 1;
5487                 goto bailout;
5488         }
5489
5490         disresponse = malloc(sizeof(*disresponse));
5491         if (disresponse == NULL) {
5492                 warn("%s: unable to allocate %zd bytes", __func__,
5493                      sizeof(*disresponse));
5494                 retval = 1;
5495                 goto bailout;
5496         }
5497
5498         for (i = 0; i < num_phys; i++) {
5499                 struct cam_devitem *item;
5500                 struct device_match_result *dev_match;
5501                 char vendor[16], product[48], revision[16];
5502                 char tmpstr[256];
5503                 int j;
5504
5505                 bzero(&(&ccb->ccb_h)[1],
5506                       sizeof(union ccb) - sizeof(struct ccb_hdr));
5507
5508                 ccb->ccb_h.status = CAM_REQ_INPROG;
5509                 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
5510
5511                 smp_discover(&ccb->smpio,
5512                              retry_count,
5513                              /*cbfcnp*/ NULL,
5514                              disrequest,
5515                              sizeof(*disrequest),
5516                              (uint8_t *)disresponse,
5517                              sizeof(*disresponse),
5518                              long_response,
5519                              /*ignore_zone_group*/ 0,
5520                              /*phy*/ i,
5521                              timeout);
5522
5523                 if (((retval = cam_send_ccb(device, ccb)) < 0)
5524                  || (((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
5525                   && (disresponse->function_result != SMP_FR_PHY_VACANT))) {
5526                         const char warnstr[] = "error sending command";
5527
5528                         if (retval < 0)
5529                                 warn(warnstr);
5530                         else
5531                                 warnx(warnstr);
5532
5533                         if (arglist & CAM_ARG_VERBOSE) {
5534                                 cam_error_print(device, ccb, CAM_ESF_ALL,
5535                                                 CAM_EPF_ALL, stderr);
5536                         }
5537                         retval = 1;
5538                         goto bailout;
5539                 }
5540
5541                 if (disresponse->function_result == SMP_FR_PHY_VACANT) {
5542                         if (quiet == 0)
5543                                 fprintf(stdout, "%3d  <vacant>\n", i);
5544                         continue;
5545                 }
5546
5547                 item = findsasdevice(&devlist,
5548                         scsi_8btou64(disresponse->attached_sas_address));
5549
5550                 if ((quiet == 0)
5551                  || (item != NULL)) {
5552                         fprintf(stdout, "%3d  0x%016jx", i,
5553                                 (uintmax_t)scsi_8btou64(
5554                                 disresponse->attached_sas_address));
5555                         if (item == NULL) {
5556                                 fprintf(stdout, "\n");
5557                                 continue;
5558                         }
5559                 } else if (quiet != 0)
5560                         continue;
5561
5562                 dev_match = &item->dev_match;
5563
5564                 if (dev_match->protocol == PROTO_SCSI) {
5565                         cam_strvis(vendor, dev_match->inq_data.vendor,
5566                                    sizeof(dev_match->inq_data.vendor),
5567                                    sizeof(vendor));
5568                         cam_strvis(product, dev_match->inq_data.product,
5569                                    sizeof(dev_match->inq_data.product),
5570                                    sizeof(product));
5571                         cam_strvis(revision, dev_match->inq_data.revision,
5572                                    sizeof(dev_match->inq_data.revision),
5573                                    sizeof(revision));
5574                         sprintf(tmpstr, "<%s %s %s>", vendor, product,
5575                                 revision);
5576                 } else if ((dev_match->protocol == PROTO_ATA)
5577                         || (dev_match->protocol == PROTO_SATAPM)) {
5578                         cam_strvis(product, dev_match->ident_data.model,
5579                                    sizeof(dev_match->ident_data.model),
5580                                    sizeof(product));
5581                         cam_strvis(revision, dev_match->ident_data.revision,
5582                                    sizeof(dev_match->ident_data.revision),
5583                                    sizeof(revision));
5584                         sprintf(tmpstr, "<%s %s>", product, revision);
5585                 } else {
5586                         sprintf(tmpstr, "<>");
5587                 }
5588                 fprintf(stdout, "   %-33s ", tmpstr);
5589
5590                 /*
5591                  * If we have 0 periphs, that's a bug...
5592                  */
5593                 if (item->num_periphs == 0) {
5594                         fprintf(stdout, "\n");
5595                         continue;
5596                 }
5597
5598                 fprintf(stdout, "(");
5599                 for (j = 0; j < item->num_periphs; j++) {
5600                         if (j > 0)
5601                                 fprintf(stdout, ",");
5602
5603                         fprintf(stdout, "%s%d",
5604                                 item->periph_matches[j].periph_name,
5605                                 item->periph_matches[j].unit_number);
5606                                 
5607                 }
5608                 fprintf(stdout, ")\n");
5609         }
5610 bailout:
5611         if (ccb != NULL)
5612                 cam_freeccb(ccb);
5613
5614         free(rgrequest);
5615
5616         free(rgresponse);
5617
5618         free(disrequest);
5619
5620         free(disresponse);
5621
5622         freebusdevlist(&devlist);
5623
5624         return (retval);
5625 }
5626
5627 static int
5628 atapm(struct cam_device *device, int argc, char **argv,
5629                  char *combinedopt, int retry_count, int timeout)
5630 {
5631         union ccb *ccb;
5632         int retval = 0;
5633         int t = -1;
5634         int c;
5635         u_char cmd, sc;
5636
5637         ccb = cam_getccb(device);
5638
5639         if (ccb == NULL) {
5640                 warnx("%s: error allocating ccb", __func__);
5641                 return (1);
5642         }
5643
5644         while ((c = getopt(argc, argv, combinedopt)) != -1) {
5645                 switch (c) {
5646                 case 't':
5647                         t = atoi(optarg);
5648                         break;
5649                 default:
5650                         break;
5651                 }
5652         }
5653         if (strcmp(argv[1], "idle") == 0) {
5654                 if (t == -1)
5655                         cmd = ATA_IDLE_IMMEDIATE;
5656                 else
5657                         cmd = ATA_IDLE_CMD;
5658         } else if (strcmp(argv[1], "standby") == 0) {
5659                 if (t == -1)
5660                         cmd = ATA_STANDBY_IMMEDIATE;
5661                 else
5662                         cmd = ATA_STANDBY_CMD;
5663         } else {
5664                 cmd = ATA_SLEEP;
5665                 t = -1;
5666         }
5667
5668         if (t < 0)
5669                 sc = 0;
5670         else if (t <= (240 * 5))
5671                 sc = (t + 4) / 5;
5672         else if (t <= (252 * 5))
5673                 /* special encoding for 21 minutes */
5674                 sc = 252;
5675         else if (t <= (11 * 30 * 60))
5676                 sc = (t - 1) / (30 * 60) + 241;
5677         else
5678                 sc = 253;
5679
5680         cam_fill_ataio(&ccb->ataio,
5681                       retry_count,
5682                       NULL,
5683                       /*flags*/CAM_DIR_NONE,
5684                       MSG_SIMPLE_Q_TAG,
5685                       /*data_ptr*/NULL,
5686                       /*dxfer_len*/0,
5687                       timeout ? timeout : 30 * 1000);
5688         ata_28bit_cmd(&ccb->ataio, cmd, 0, 0, sc);
5689
5690         /* Disable freezing the device queue */
5691         ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
5692
5693         if (arglist & CAM_ARG_ERR_RECOVER)
5694                 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
5695
5696         if (cam_send_ccb(device, ccb) < 0) {
5697                 warn("error sending command");
5698
5699                 if (arglist & CAM_ARG_VERBOSE)
5700                         cam_error_print(device, ccb, CAM_ESF_ALL,
5701                                         CAM_EPF_ALL, stderr);
5702
5703                 retval = 1;
5704                 goto bailout;
5705         }
5706
5707         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
5708                 cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
5709                 retval = 1;
5710                 goto bailout;
5711         }
5712 bailout:
5713         cam_freeccb(ccb);
5714         return (retval);
5715 }
5716
5717 #endif /* MINIMALISTIC */
5718
5719 void
5720 usage(int verbose)
5721 {
5722         fprintf(verbose ? stdout : stderr,
5723 "usage:  camcontrol <command>  [device id][generic args][command args]\n"
5724 "        camcontrol devlist    [-v]\n"
5725 #ifndef MINIMALISTIC
5726 "        camcontrol periphlist [dev_id][-n dev_name] [-u unit]\n"
5727 "        camcontrol tur        [dev_id][generic args]\n"
5728 "        camcontrol inquiry    [dev_id][generic args] [-D] [-S] [-R]\n"
5729 "        camcontrol identify   [dev_id][generic args] [-v]\n"
5730 "        camcontrol reportluns [dev_id][generic args] [-c] [-l] [-r report]\n"
5731 "        camcontrol readcap    [dev_id][generic args] [-b] [-h] [-H] [-N]\n"
5732 "                              [-q] [-s]\n"
5733 "        camcontrol start      [dev_id][generic args]\n"
5734 "        camcontrol stop       [dev_id][generic args]\n"
5735 "        camcontrol load       [dev_id][generic args]\n"
5736 "        camcontrol eject      [dev_id][generic args]\n"
5737 #endif /* MINIMALISTIC */
5738 "        camcontrol rescan     <all | bus[:target:lun]>\n"
5739 "        camcontrol reset      <all | bus[:target:lun]>\n"
5740 #ifndef MINIMALISTIC
5741 "        camcontrol defects    [dev_id][generic args] <-f format> [-P][-G]\n"
5742 "        camcontrol modepage   [dev_id][generic args] <-m page | -l>\n"
5743 "                              [-P pagectl][-e | -b][-d]\n"
5744 "        camcontrol cmd        [dev_id][generic args]\n"
5745 "                              <-a cmd [args] | -c cmd [args]>\n"
5746 "                              [-d] [-f] [-i len fmt|-o len fmt [args]] [-r fmt]\n"
5747 "        camcontrol smpcmd     [dev_id][generic args]\n"
5748 "                              <-r len fmt [args]> <-R len fmt [args]>\n"
5749 "        camcontrol smprg      [dev_id][generic args][-l]\n"
5750 "        camcontrol smppc      [dev_id][generic args] <-p phy> [-l]\n"
5751 "                              [-o operation][-d name][-m rate][-M rate]\n"
5752 "                              [-T pp_timeout][-a enable|disable]\n"
5753 "                              [-A enable|disable][-s enable|disable]\n"
5754 "                              [-S enable|disable]\n"
5755 "        camcontrol smpphylist [dev_id][generic args][-l][-q]\n"
5756 "        camcontrol smpmaninfo [dev_id][generic args][-l]\n"
5757 "        camcontrol debug      [-I][-P][-T][-S][-X][-c]\n"
5758 "                              <all|bus[:target[:lun]]|off>\n"
5759 "        camcontrol tags       [dev_id][generic args] [-N tags] [-q] [-v]\n"
5760 "        camcontrol negotiate  [dev_id][generic args] [-a][-c]\n"
5761 "                              [-D <enable|disable>][-M mode][-O offset]\n"
5762 "                              [-q][-R syncrate][-v][-T <enable|disable>]\n"
5763 "                              [-U][-W bus_width]\n"
5764 "        camcontrol format     [dev_id][generic args][-q][-r][-w][-y]\n"
5765 "        camcontrol idle       [dev_id][generic args][-t time]\n"
5766 "        camcontrol standby    [dev_id][generic args][-t time]\n"
5767 "        camcontrol sleep      [dev_id][generic args]\n"
5768 "        camcontrol fwdownload [dev_id][generic args] <-f fw_image> [-y][-s]\n"
5769 #endif /* MINIMALISTIC */
5770 "        camcontrol help\n");
5771         if (!verbose)
5772                 return;
5773 #ifndef MINIMALISTIC
5774         fprintf(stdout,
5775 "Specify one of the following options:\n"
5776 "devlist     list all CAM devices\n"
5777 "periphlist  list all CAM peripheral drivers attached to a device\n"
5778 "tur         send a test unit ready to the named device\n"
5779 "inquiry     send a SCSI inquiry command to the named device\n"
5780 "identify    send a ATA identify command to the named device\n"
5781 "reportluns  send a SCSI report luns command to the device\n"
5782 "readcap     send a SCSI read capacity command to the device\n"
5783 "start       send a Start Unit command to the device\n"
5784 "stop        send a Stop Unit command to the device\n"
5785 "load        send a Start Unit command to the device with the load bit set\n"
5786 "eject       send a Stop Unit command to the device with the eject bit set\n"
5787 "rescan      rescan all busses, the given bus, or bus:target:lun\n"
5788 "reset       reset all busses, the given bus, or bus:target:lun\n"
5789 "defects     read the defect list of the specified device\n"
5790 "modepage    display or edit (-e) the given mode page\n"
5791 "cmd         send the given SCSI command, may need -i or -o as well\n"
5792 "smpcmd      send the given SMP command, requires -o and -i\n"
5793 "smprg       send the SMP Report General command\n"
5794 "smppc       send the SMP PHY Control command, requires -p\n"
5795 "smpphylist  display phys attached to a SAS expander\n"
5796 "smpmaninfo  send the SMP Report Manufacturer Info command\n"
5797 "debug       turn debugging on/off for a bus, target, or lun, or all devices\n"
5798 "tags        report or set the number of transaction slots for a device\n"
5799 "negotiate   report or set device negotiation parameters\n"
5800 "format      send the SCSI FORMAT UNIT command to the named device\n"
5801 "idle        send the ATA IDLE command to the named device\n"
5802 "standby     send the ATA STANDBY command to the named device\n"
5803 "sleep       send the ATA SLEEP command to the named device\n"
5804 "fwdownload  program firmware of the named device with the given image"
5805 "help        this message\n"
5806 "Device Identifiers:\n"
5807 "bus:target        specify the bus and target, lun defaults to 0\n"
5808 "bus:target:lun    specify the bus, target and lun\n"
5809 "deviceUNIT        specify the device name, like \"da4\" or \"cd2\"\n"
5810 "Generic arguments:\n"
5811 "-v                be verbose, print out sense information\n"
5812 "-t timeout        command timeout in seconds, overrides default timeout\n"
5813 "-n dev_name       specify device name, e.g. \"da\", \"cd\"\n"
5814 "-u unit           specify unit number, e.g. \"0\", \"5\"\n"
5815 "-E                have the kernel attempt to perform SCSI error recovery\n"
5816 "-C count          specify the SCSI command retry count (needs -E to work)\n"
5817 "modepage arguments:\n"
5818 "-l                list all available mode pages\n"
5819 "-m page           specify the mode page to view or edit\n"
5820 "-e                edit the specified mode page\n"
5821 "-b                force view to binary mode\n"
5822 "-d                disable block descriptors for mode sense\n"
5823 "-P pgctl          page control field 0-3\n"
5824 "defects arguments:\n"
5825 "-f format         specify defect list format (block, bfi or phys)\n"
5826 "-G                get the grown defect list\n"
5827 "-P                get the permanant defect list\n"
5828 "inquiry arguments:\n"
5829 "-D                get the standard inquiry data\n"
5830 "-S                get the serial number\n"
5831 "-R                get the transfer rate, etc.\n"
5832 "reportluns arguments:\n"
5833 "-c                only report a count of available LUNs\n"
5834 "-l                only print out luns, and not a count\n"
5835 "-r <reporttype>   specify \"default\", \"wellknown\" or \"all\"\n"
5836 "readcap arguments\n"
5837 "-b                only report the blocksize\n"
5838 "-h                human readable device size, base 2\n"
5839 "-H                human readable device size, base 10\n"
5840 "-N                print the number of blocks instead of last block\n"
5841 "-q                quiet, print numbers only\n"
5842 "-s                only report the last block/device size\n"
5843 "cmd arguments:\n"
5844 "-c cdb [args]     specify the SCSI CDB\n"
5845 "-i len fmt        specify input data and input data format\n"
5846 "-o len fmt [args] specify output data and output data fmt\n"
5847 "smpcmd arguments:\n"
5848 "-r len fmt [args] specify the SMP command to be sent\n"
5849 "-R len fmt [args] specify SMP response format\n"
5850 "smprg arguments:\n"
5851 "-l                specify the long response format\n"
5852 "smppc arguments:\n"
5853 "-p phy            specify the PHY to operate on\n"
5854 "-l                specify the long request/response format\n"
5855 "-o operation      specify the phy control operation\n"
5856 "-d name           set the attached device name\n"
5857 "-m rate           set the minimum physical link rate\n"
5858 "-M rate           set the maximum physical link rate\n"
5859 "-T pp_timeout     set the partial pathway timeout value\n"
5860 "-a enable|disable enable or disable SATA slumber\n"
5861 "-A enable|disable enable or disable SATA partial phy power\n"
5862 "-s enable|disable enable or disable SAS slumber\n"
5863 "-S enable|disable enable or disable SAS partial phy power\n"
5864 "smpphylist arguments:\n"
5865 "-l                specify the long response format\n"
5866 "-q                only print phys with attached devices\n"
5867 "smpmaninfo arguments:\n"
5868 "-l                specify the long response format\n"
5869 "debug arguments:\n"
5870 "-I                CAM_DEBUG_INFO -- scsi commands, errors, data\n"
5871 "-T                CAM_DEBUG_TRACE -- routine flow tracking\n"
5872 "-S                CAM_DEBUG_SUBTRACE -- internal routine command flow\n"
5873 "-c                CAM_DEBUG_CDB -- print out SCSI CDBs only\n"
5874 "tags arguments:\n"
5875 "-N tags           specify the number of tags to use for this device\n"
5876 "-q                be quiet, don't report the number of tags\n"
5877 "-v                report a number of tag-related parameters\n"
5878 "negotiate arguments:\n"
5879 "-a                send a test unit ready after negotiation\n"
5880 "-c                report/set current negotiation settings\n"
5881 "-D <arg>          \"enable\" or \"disable\" disconnection\n"
5882 "-M mode           set ATA mode\n"
5883 "-O offset         set command delay offset\n"
5884 "-q                be quiet, don't report anything\n"
5885 "-R syncrate       synchronization rate in MHz\n"
5886 "-T <arg>          \"enable\" or \"disable\" tagged queueing\n"
5887 "-U                report/set user negotiation settings\n"
5888 "-W bus_width      set the bus width in bits (8, 16 or 32)\n"
5889 "-v                also print a Path Inquiry CCB for the controller\n"
5890 "format arguments:\n"
5891 "-q                be quiet, don't print status messages\n"
5892 "-r                run in report only mode\n"
5893 "-w                don't send immediate format command\n"
5894 "-y                don't ask any questions\n"
5895 "idle/standby arguments:\n"
5896 "-t <arg>          number of seconds before respective state.\n"
5897 "fwdownload arguments:\n"
5898 "-f fw_image       path to firmware image file\n"
5899 "-y                don't ask any questions\n"
5900 "-s                run in simulation mode\n"
5901 "-v                print info for every firmware segment sent to device\n");
5902 #endif /* MINIMALISTIC */
5903 }
5904
5905 int
5906 main(int argc, char **argv)
5907 {
5908         int c;
5909         char *device = NULL;
5910         int unit = 0;
5911         struct cam_device *cam_dev = NULL;
5912         int timeout = 0, retry_count = 1;
5913         camcontrol_optret optreturn;
5914         char *tstr;
5915         const char *mainopt = "C:En:t:u:v";
5916         const char *subopt = NULL;
5917         char combinedopt[256];
5918         int error = 0, optstart = 2;
5919         int devopen = 1;
5920 #ifndef MINIMALISTIC
5921         int bus, target, lun;
5922 #endif /* MINIMALISTIC */
5923
5924         cmdlist = CAM_CMD_NONE;
5925         arglist = CAM_ARG_NONE;
5926
5927         if (argc < 2) {
5928                 usage(0);
5929                 exit(1);
5930         }
5931
5932         /*
5933          * Get the base option.
5934          */
5935         optreturn = getoption(option_table,argv[1], &cmdlist, &arglist,&subopt);
5936
5937         if (optreturn == CC_OR_AMBIGUOUS) {
5938                 warnx("ambiguous option %s", argv[1]);
5939                 usage(0);
5940                 exit(1);
5941         } else if (optreturn == CC_OR_NOT_FOUND) {
5942                 warnx("option %s not found", argv[1]);
5943                 usage(0);
5944                 exit(1);
5945         }
5946
5947         /*
5948          * Ahh, getopt(3) is a pain.
5949          *
5950          * This is a gross hack.  There really aren't many other good
5951          * options (excuse the pun) for parsing options in a situation like
5952          * this.  getopt is kinda braindead, so you end up having to run
5953          * through the options twice, and give each invocation of getopt
5954          * the option string for the other invocation.
5955          *
5956          * You would think that you could just have two groups of options.
5957          * The first group would get parsed by the first invocation of
5958          * getopt, and the second group would get parsed by the second
5959          * invocation of getopt.  It doesn't quite work out that way.  When
5960          * the first invocation of getopt finishes, it leaves optind pointing
5961          * to the argument _after_ the first argument in the second group.
5962          * So when the second invocation of getopt comes around, it doesn't
5963          * recognize the first argument it gets and then bails out.
5964          *
5965          * A nice alternative would be to have a flag for getopt that says
5966          * "just keep parsing arguments even when you encounter an unknown
5967          * argument", but there isn't one.  So there's no real clean way to
5968          * easily parse two sets of arguments without having one invocation
5969          * of getopt know about the other.
5970          *
5971          * Without this hack, the first invocation of getopt would work as
5972          * long as the generic arguments are first, but the second invocation
5973          * (in the subfunction) would fail in one of two ways.  In the case
5974          * where you don't set optreset, it would fail because optind may be
5975          * pointing to the argument after the one it should be pointing at.
5976          * In the case where you do set optreset, and reset optind, it would
5977          * fail because getopt would run into the first set of options, which
5978          * it doesn't understand.
5979          *
5980          * All of this would "sort of" work if you could somehow figure out
5981          * whether optind had been incremented one option too far.  The
5982          * mechanics of that, however, are more daunting than just giving
5983          * both invocations all of the expect options for either invocation.
5984          *
5985          * Needless to say, I wouldn't mind if someone invented a better
5986          * (non-GPL!) command line parsing interface than getopt.  I
5987          * wouldn't mind if someone added more knobs to getopt to make it
5988          * work better.  Who knows, I may talk myself into doing it someday,
5989          * if the standards weenies let me.  As it is, it just leads to
5990          * hackery like this and causes people to avoid it in some cases.
5991          *
5992          * KDM, September 8th, 1998
5993          */
5994         if (subopt != NULL)
5995                 sprintf(combinedopt, "%s%s", mainopt, subopt);
5996         else
5997                 sprintf(combinedopt, "%s", mainopt);
5998
5999         /*
6000          * For these options we do not parse optional device arguments and
6001          * we do not open a passthrough device.
6002          */
6003         if ((cmdlist == CAM_CMD_RESCAN)
6004          || (cmdlist == CAM_CMD_RESET)
6005          || (cmdlist == CAM_CMD_DEVTREE)
6006          || (cmdlist == CAM_CMD_USAGE)
6007          || (cmdlist == CAM_CMD_DEBUG))
6008                 devopen = 0;
6009
6010 #ifndef MINIMALISTIC
6011         if ((devopen == 1)
6012          && (argc > 2 && argv[2][0] != '-')) {
6013                 char name[30];
6014                 int rv;
6015
6016                 if (isdigit(argv[2][0])) {
6017                         /* device specified as bus:target[:lun] */
6018                         rv = parse_btl(argv[2], &bus, &target, &lun, &arglist);
6019                         if (rv < 2)
6020                                 errx(1, "numeric device specification must "
6021                                      "be either bus:target, or "
6022                                      "bus:target:lun");
6023                         /* default to 0 if lun was not specified */
6024                         if ((arglist & CAM_ARG_LUN) == 0) {
6025                                 lun = 0;
6026                                 arglist |= CAM_ARG_LUN;
6027                         }
6028                         optstart++;
6029                 } else {
6030                         if (cam_get_device(argv[2], name, sizeof name, &unit)
6031                             == -1)
6032                                 errx(1, "%s", cam_errbuf);
6033                         device = strdup(name);
6034                         arglist |= CAM_ARG_DEVICE | CAM_ARG_UNIT;
6035                         optstart++;
6036                 }
6037         }
6038 #endif /* MINIMALISTIC */
6039         /*
6040          * Start getopt processing at argv[2/3], since we've already
6041          * accepted argv[1..2] as the command name, and as a possible
6042          * device name.
6043          */
6044         optind = optstart;
6045
6046         /*
6047          * Now we run through the argument list looking for generic
6048          * options, and ignoring options that possibly belong to
6049          * subfunctions.
6050          */
6051         while ((c = getopt(argc, argv, combinedopt))!= -1){
6052                 switch(c) {
6053                         case 'C':
6054                                 retry_count = strtol(optarg, NULL, 0);
6055                                 if (retry_count < 0)
6056                                         errx(1, "retry count %d is < 0",
6057                                              retry_count);
6058                                 arglist |= CAM_ARG_RETRIES;
6059                                 break;
6060                         case 'E':
6061                                 arglist |= CAM_ARG_ERR_RECOVER;
6062                                 break;
6063                         case 'n':
6064                                 arglist |= CAM_ARG_DEVICE;
6065                                 tstr = optarg;
6066                                 while (isspace(*tstr) && (*tstr != '\0'))
6067                                         tstr++;
6068                                 device = (char *)strdup(tstr);
6069                                 break;
6070                         case 't':
6071                                 timeout = strtol(optarg, NULL, 0);
6072                                 if (timeout < 0)
6073                                         errx(1, "invalid timeout %d", timeout);
6074                                 /* Convert the timeout from seconds to ms */
6075                                 timeout *= 1000;
6076                                 arglist |= CAM_ARG_TIMEOUT;
6077                                 break;
6078                         case 'u':
6079                                 arglist |= CAM_ARG_UNIT;
6080                                 unit = strtol(optarg, NULL, 0);
6081                                 break;
6082                         case 'v':
6083                                 arglist |= CAM_ARG_VERBOSE;
6084                                 break;
6085                         default:
6086                                 break;
6087                 }
6088         }
6089
6090 #ifndef MINIMALISTIC
6091         /*
6092          * For most commands we'll want to open the passthrough device
6093          * associated with the specified device.  In the case of the rescan
6094          * commands, we don't use a passthrough device at all, just the
6095          * transport layer device.
6096          */
6097         if (devopen == 1) {
6098                 if (((arglist & (CAM_ARG_BUS|CAM_ARG_TARGET)) == 0)
6099                  && (((arglist & CAM_ARG_DEVICE) == 0)
6100                   || ((arglist & CAM_ARG_UNIT) == 0))) {
6101                         errx(1, "subcommand \"%s\" requires a valid device "
6102                              "identifier", argv[1]);
6103                 }
6104
6105                 if ((cam_dev = ((arglist & (CAM_ARG_BUS | CAM_ARG_TARGET))?
6106                                 cam_open_btl(bus, target, lun, O_RDWR, NULL) :
6107                                 cam_open_spec_device(device,unit,O_RDWR,NULL)))
6108                      == NULL)
6109                         errx(1,"%s", cam_errbuf);
6110         }
6111 #endif /* MINIMALISTIC */
6112
6113         /*
6114          * Reset optind to 2, and reset getopt, so these routines can parse
6115          * the arguments again.
6116          */
6117         optind = optstart;
6118         optreset = 1;
6119
6120         switch(cmdlist) {
6121 #ifndef MINIMALISTIC
6122                 case CAM_CMD_DEVLIST:
6123                         error = getdevlist(cam_dev);
6124                         break;
6125 #endif /* MINIMALISTIC */
6126                 case CAM_CMD_DEVTREE:
6127                         error = getdevtree();
6128                         break;
6129 #ifndef MINIMALISTIC
6130                 case CAM_CMD_TUR:
6131                         error = testunitready(cam_dev, retry_count, timeout, 0);
6132                         break;
6133                 case CAM_CMD_INQUIRY:
6134                         error = scsidoinquiry(cam_dev, argc, argv, combinedopt,
6135                                               retry_count, timeout);
6136                         break;
6137                 case CAM_CMD_IDENTIFY:
6138                         error = ataidentify(cam_dev, retry_count, timeout);
6139                         break;
6140                 case CAM_CMD_STARTSTOP:
6141                         error = scsistart(cam_dev, arglist & CAM_ARG_START_UNIT,
6142                                           arglist & CAM_ARG_EJECT, retry_count,
6143                                           timeout);
6144                         break;
6145 #endif /* MINIMALISTIC */
6146                 case CAM_CMD_RESCAN:
6147                         error = dorescan_or_reset(argc, argv, 1);
6148                         break;
6149                 case CAM_CMD_RESET:
6150                         error = dorescan_or_reset(argc, argv, 0);
6151                         break;
6152 #ifndef MINIMALISTIC
6153                 case CAM_CMD_READ_DEFECTS:
6154                         error = readdefects(cam_dev, argc, argv, combinedopt,
6155                                             retry_count, timeout);
6156                         break;
6157                 case CAM_CMD_MODE_PAGE:
6158                         modepage(cam_dev, argc, argv, combinedopt,
6159                                  retry_count, timeout);
6160                         break;
6161                 case CAM_CMD_SCSI_CMD:
6162                         error = scsicmd(cam_dev, argc, argv, combinedopt,
6163                                         retry_count, timeout);
6164                         break;
6165                 case CAM_CMD_SMP_CMD:
6166                         error = smpcmd(cam_dev, argc, argv, combinedopt,
6167                                        retry_count, timeout);
6168                         break;
6169                 case CAM_CMD_SMP_RG:
6170                         error = smpreportgeneral(cam_dev, argc, argv,
6171                                                  combinedopt, retry_count,
6172                                                  timeout);
6173                         break;
6174                 case CAM_CMD_SMP_PC:
6175                         error = smpphycontrol(cam_dev, argc, argv, combinedopt, 
6176                                               retry_count, timeout);
6177                         break;
6178                 case CAM_CMD_SMP_PHYLIST:
6179                         error = smpphylist(cam_dev, argc, argv, combinedopt,
6180                                            retry_count, timeout);
6181                         break;
6182                 case CAM_CMD_SMP_MANINFO:
6183                         error = smpmaninfo(cam_dev, argc, argv, combinedopt,
6184                                            retry_count, timeout);
6185                         break;
6186                 case CAM_CMD_DEBUG:
6187                         error = camdebug(argc, argv, combinedopt);
6188                         break;
6189                 case CAM_CMD_TAG:
6190                         error = tagcontrol(cam_dev, argc, argv, combinedopt);
6191                         break;
6192                 case CAM_CMD_RATE:
6193                         error = ratecontrol(cam_dev, retry_count, timeout,
6194                                             argc, argv, combinedopt);
6195                         break;
6196                 case CAM_CMD_FORMAT:
6197                         error = scsiformat(cam_dev, argc, argv,
6198                                            combinedopt, retry_count, timeout);
6199                         break;
6200                 case CAM_CMD_REPORTLUNS:
6201                         error = scsireportluns(cam_dev, argc, argv,
6202                                                combinedopt, retry_count,
6203                                                timeout);
6204                         break;
6205                 case CAM_CMD_READCAP:
6206                         error = scsireadcapacity(cam_dev, argc, argv,
6207                                                  combinedopt, retry_count,
6208                                                  timeout);
6209                         break;
6210                 case CAM_CMD_IDLE:
6211                 case CAM_CMD_STANDBY:
6212                 case CAM_CMD_SLEEP:
6213                         error = atapm(cam_dev, argc, argv,
6214                                                  combinedopt, retry_count,
6215                                                  timeout);
6216                         break;
6217                 case CAM_CMD_DOWNLOAD_FW:
6218                         error = fwdownload(cam_dev, argc, argv, combinedopt,
6219                             arglist & CAM_ARG_VERBOSE, retry_count, timeout,
6220                             get_disk_type(cam_dev));
6221                         break;
6222 #endif /* MINIMALISTIC */
6223                 case CAM_CMD_USAGE:
6224                         usage(1);
6225                         break;
6226                 default:
6227                         usage(0);
6228                         error = 1;
6229                         break;
6230         }
6231
6232         if (cam_dev != NULL)
6233                 cam_close_device(cam_dev);
6234
6235         exit(error);
6236 }