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