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