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