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