camcontrol.c revision 236437
139214Sgibbs/* 2172093Sken * Copyright (c) 1997-2007 Kenneth D. Merry 339214Sgibbs * All rights reserved. 439214Sgibbs * 539214Sgibbs * Redistribution and use in source and binary forms, with or without 639214Sgibbs * modification, are permitted provided that the following conditions 739214Sgibbs * are met: 839214Sgibbs * 1. Redistributions of source code must retain the above copyright 939214Sgibbs * notice, this list of conditions and the following disclaimer. 1039214Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1139214Sgibbs * notice, this list of conditions and the following disclaimer in the 1239214Sgibbs * documentation and/or other materials provided with the distribution. 1339214Sgibbs * 3. The name of the author may not be used to endorse or promote products 1439214Sgibbs * derived from this software without specific prior written permission. 1539214Sgibbs * 1639214Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1739214Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1839214Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1939214Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2039214Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2139214Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2239214Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2339214Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2439214Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2539214Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2639214Sgibbs * SUCH DAMAGE. 2739214Sgibbs */ 2839214Sgibbs 29114513Sobrien#include <sys/cdefs.h> 30114513Sobrien__FBSDID("$FreeBSD: head/sbin/camcontrol/camcontrol.c 236437 2012-06-02 08:29:07Z mav $"); 31114513Sobrien 3239214Sgibbs#include <sys/ioctl.h> 33111195Sjohan#include <sys/stdint.h> 3439214Sgibbs#include <sys/types.h> 35195534Sscottl#include <sys/endian.h> 36216088Sken#include <sys/sbuf.h> 37111195Sjohan 3839214Sgibbs#include <stdio.h> 3939214Sgibbs#include <stdlib.h> 4039214Sgibbs#include <string.h> 4139214Sgibbs#include <unistd.h> 42216088Sken#include <inttypes.h> 43216088Sken#include <limits.h> 4439214Sgibbs#include <fcntl.h> 4539214Sgibbs#include <ctype.h> 4639214Sgibbs#include <err.h> 47172093Sken#include <libutil.h> 4839214Sgibbs 4939214Sgibbs#include <cam/cam.h> 5039214Sgibbs#include <cam/cam_debug.h> 5139214Sgibbs#include <cam/cam_ccb.h> 5239214Sgibbs#include <cam/scsi/scsi_all.h> 5339214Sgibbs#include <cam/scsi/scsi_da.h> 5439214Sgibbs#include <cam/scsi/scsi_pass.h> 5539214Sgibbs#include <cam/scsi/scsi_message.h> 56216088Sken#include <cam/scsi/smp_all.h> 57195534Sscottl#include <cam/ata/ata_all.h> 5839214Sgibbs#include <camlib.h> 5939214Sgibbs#include "camcontrol.h" 6039214Sgibbs 6139214Sgibbstypedef enum { 62103092Smdodd CAM_CMD_NONE = 0x00000000, 63103092Smdodd CAM_CMD_DEVLIST = 0x00000001, 64103092Smdodd CAM_CMD_TUR = 0x00000002, 65103092Smdodd CAM_CMD_INQUIRY = 0x00000003, 66103092Smdodd CAM_CMD_STARTSTOP = 0x00000004, 67103092Smdodd CAM_CMD_RESCAN = 0x00000005, 68103092Smdodd CAM_CMD_READ_DEFECTS = 0x00000006, 69103092Smdodd CAM_CMD_MODE_PAGE = 0x00000007, 70103092Smdodd CAM_CMD_SCSI_CMD = 0x00000008, 71103092Smdodd CAM_CMD_DEVTREE = 0x00000009, 72103092Smdodd CAM_CMD_USAGE = 0x0000000a, 73103092Smdodd CAM_CMD_DEBUG = 0x0000000b, 74103092Smdodd CAM_CMD_RESET = 0x0000000c, 75103092Smdodd CAM_CMD_FORMAT = 0x0000000d, 76103092Smdodd CAM_CMD_TAG = 0x0000000e, 77103092Smdodd CAM_CMD_RATE = 0x0000000f, 78103092Smdodd CAM_CMD_DETACH = 0x00000010, 79172093Sken CAM_CMD_REPORTLUNS = 0x00000011, 80195534Sscottl CAM_CMD_READCAP = 0x00000012, 81199079Smav CAM_CMD_IDENTIFY = 0x00000013, 82199079Smav CAM_CMD_IDLE = 0x00000014, 83199079Smav CAM_CMD_STANDBY = 0x00000015, 84216088Sken CAM_CMD_SLEEP = 0x00000016, 85216088Sken CAM_CMD_SMP_CMD = 0x00000017, 86216088Sken CAM_CMD_SMP_RG = 0x00000018, 87216088Sken CAM_CMD_SMP_PC = 0x00000019, 88216088Sken CAM_CMD_SMP_PHYLIST = 0x0000001a, 89227961Semaste CAM_CMD_SMP_MANINFO = 0x0000001b, 90227961Semaste CAM_CMD_DOWNLOAD_FW = 0x0000001c 91103092Smdodd} cam_cmdmask; 92103092Smdodd 93103092Smdoddtypedef enum { 9439214Sgibbs CAM_ARG_NONE = 0x00000000, 95103092Smdodd CAM_ARG_VERBOSE = 0x00000001, 96103092Smdodd CAM_ARG_DEVICE = 0x00000002, 97103092Smdodd CAM_ARG_BUS = 0x00000004, 98103092Smdodd CAM_ARG_TARGET = 0x00000008, 99103092Smdodd CAM_ARG_LUN = 0x00000010, 100103092Smdodd CAM_ARG_EJECT = 0x00000020, 101103092Smdodd CAM_ARG_UNIT = 0x00000040, 102103092Smdodd CAM_ARG_FORMAT_BLOCK = 0x00000080, 103103092Smdodd CAM_ARG_FORMAT_BFI = 0x00000100, 104103092Smdodd CAM_ARG_FORMAT_PHYS = 0x00000200, 105103092Smdodd CAM_ARG_PLIST = 0x00000400, 106103092Smdodd CAM_ARG_GLIST = 0x00000800, 107103092Smdodd CAM_ARG_GET_SERIAL = 0x00001000, 108103092Smdodd CAM_ARG_GET_STDINQ = 0x00002000, 109103092Smdodd CAM_ARG_GET_XFERRATE = 0x00004000, 110103092Smdodd CAM_ARG_INQ_MASK = 0x00007000, 111103092Smdodd CAM_ARG_MODE_EDIT = 0x00008000, 112103092Smdodd CAM_ARG_PAGE_CNTL = 0x00010000, 113103092Smdodd CAM_ARG_TIMEOUT = 0x00020000, 114103092Smdodd CAM_ARG_CMD_IN = 0x00040000, 115103092Smdodd CAM_ARG_CMD_OUT = 0x00080000, 116103092Smdodd CAM_ARG_DBD = 0x00100000, 117103092Smdodd CAM_ARG_ERR_RECOVER = 0x00200000, 118103092Smdodd CAM_ARG_RETRIES = 0x00400000, 119103092Smdodd CAM_ARG_START_UNIT = 0x00800000, 120103092Smdodd CAM_ARG_DEBUG_INFO = 0x01000000, 121103092Smdodd CAM_ARG_DEBUG_TRACE = 0x02000000, 122103092Smdodd CAM_ARG_DEBUG_SUBTRACE = 0x04000000, 123103092Smdodd CAM_ARG_DEBUG_CDB = 0x08000000, 124107966Snjl CAM_ARG_DEBUG_XPT = 0x10000000, 125107966Snjl CAM_ARG_DEBUG_PERIPH = 0x20000000, 12639214Sgibbs} cam_argmask; 12739214Sgibbs 12839214Sgibbsstruct camcontrol_opts { 129214321Smav const char *optname; 130216088Sken uint32_t cmdnum; 13139214Sgibbs cam_argmask argnum; 13239214Sgibbs const char *subopt; 13339214Sgibbs}; 13439214Sgibbs 13589471Sjoerg#ifndef MINIMALISTIC 136207498Smavstatic const char scsicmd_opts[] = "a:c:dfi:o:r"; 13739214Sgibbsstatic const char readdefect_opts[] = "f:GP"; 138199821Smavstatic const char negotiate_opts[] = "acD:M:O:qR:T:UW:"; 139216088Skenstatic const char smprg_opts[] = "l"; 140216088Skenstatic const char smppc_opts[] = "a:A:d:lm:M:o:p:s:S:T:"; 141216088Skenstatic const char smpphylist_opts[] = "lq"; 14289471Sjoerg#endif 14339214Sgibbs 144227081Sedstatic struct camcontrol_opts option_table[] = { 14589471Sjoerg#ifndef MINIMALISTIC 146103092Smdodd {"tur", CAM_CMD_TUR, CAM_ARG_NONE, NULL}, 147103092Smdodd {"inquiry", CAM_CMD_INQUIRY, CAM_ARG_NONE, "DSR"}, 148195534Sscottl {"identify", CAM_CMD_IDENTIFY, CAM_ARG_NONE, NULL}, 149103092Smdodd {"start", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT, NULL}, 150103092Smdodd {"stop", CAM_CMD_STARTSTOP, CAM_ARG_NONE, NULL}, 151103092Smdodd {"load", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT | CAM_ARG_EJECT, NULL}, 152103092Smdodd {"eject", CAM_CMD_STARTSTOP, CAM_ARG_EJECT, NULL}, 153161506Sken {"reportluns", CAM_CMD_REPORTLUNS, CAM_ARG_NONE, "clr:"}, 154172093Sken {"readcapacity", CAM_CMD_READCAP, CAM_ARG_NONE, "bhHNqs"}, 15589471Sjoerg#endif /* MINIMALISTIC */ 156103092Smdodd {"rescan", CAM_CMD_RESCAN, CAM_ARG_NONE, NULL}, 157103092Smdodd {"reset", CAM_CMD_RESET, CAM_ARG_NONE, NULL}, 15889471Sjoerg#ifndef MINIMALISTIC 159103092Smdodd {"cmd", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts}, 160103092Smdodd {"command", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts}, 161216088Sken {"smpcmd", CAM_CMD_SMP_CMD, CAM_ARG_NONE, "r:R:"}, 162216088Sken {"smprg", CAM_CMD_SMP_RG, CAM_ARG_NONE, smprg_opts}, 163216088Sken {"smpreportgeneral", CAM_CMD_SMP_RG, CAM_ARG_NONE, smprg_opts}, 164216088Sken {"smppc", CAM_CMD_SMP_PC, CAM_ARG_NONE, smppc_opts}, 165216088Sken {"smpphycontrol", CAM_CMD_SMP_PC, CAM_ARG_NONE, smppc_opts}, 166216088Sken {"smpplist", CAM_CMD_SMP_PHYLIST, CAM_ARG_NONE, smpphylist_opts}, 167216088Sken {"smpphylist", CAM_CMD_SMP_PHYLIST, CAM_ARG_NONE, smpphylist_opts}, 168216088Sken {"smpmaninfo", CAM_CMD_SMP_MANINFO, CAM_ARG_NONE, "l"}, 169103092Smdodd {"defects", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts}, 170103092Smdodd {"defectlist", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts}, 17189521Sjoerg#endif /* MINIMALISTIC */ 172103092Smdodd {"devlist", CAM_CMD_DEVTREE, CAM_ARG_NONE, NULL}, 17389521Sjoerg#ifndef MINIMALISTIC 174103092Smdodd {"periphlist", CAM_CMD_DEVLIST, CAM_ARG_NONE, NULL}, 175103092Smdodd {"modepage", CAM_CMD_MODE_PAGE, CAM_ARG_NONE, "bdelm:P:"}, 176103092Smdodd {"tags", CAM_CMD_TAG, CAM_ARG_NONE, "N:q"}, 177103092Smdodd {"negotiate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts}, 178103092Smdodd {"rate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts}, 179107966Snjl {"debug", CAM_CMD_DEBUG, CAM_ARG_NONE, "IPTSXc"}, 180144134Sken {"format", CAM_CMD_FORMAT, CAM_ARG_NONE, "qrwy"}, 181199079Smav {"idle", CAM_CMD_IDLE, CAM_ARG_NONE, "t:"}, 182199079Smav {"standby", CAM_CMD_STANDBY, CAM_ARG_NONE, "t:"}, 183199079Smav {"sleep", CAM_CMD_SLEEP, CAM_ARG_NONE, ""}, 184227961Semaste {"fwdownload", CAM_CMD_DOWNLOAD_FW, CAM_ARG_NONE, "f:ys"}, 18589471Sjoerg#endif /* MINIMALISTIC */ 186103092Smdodd {"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL}, 187103092Smdodd {"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL}, 188103092Smdodd {"-h", CAM_CMD_USAGE, CAM_ARG_NONE, NULL}, 189103092Smdodd {NULL, 0, 0, NULL} 19039214Sgibbs}; 19139214Sgibbs 19239214Sgibbstypedef enum { 19339214Sgibbs CC_OR_NOT_FOUND, 19439214Sgibbs CC_OR_AMBIGUOUS, 19539214Sgibbs CC_OR_FOUND 19639214Sgibbs} camcontrol_optret; 19739214Sgibbs 198216088Skenstruct cam_devitem { 199216088Sken struct device_match_result dev_match; 200216088Sken int num_periphs; 201216088Sken struct periph_match_result *periph_matches; 202216088Sken struct scsi_vpd_device_id *device_id; 203216088Sken int device_id_len; 204216088Sken STAILQ_ENTRY(cam_devitem) links; 205216088Sken}; 206216088Sken 207216088Skenstruct cam_devlist { 208216088Sken STAILQ_HEAD(, cam_devitem) dev_queue; 209216088Sken path_id_t path_id; 210216088Sken}; 211216088Sken 212227081Sedstatic cam_cmdmask cmdlist; 213227081Sedstatic cam_argmask arglist; 21439214Sgibbs 215216088Skencamcontrol_optret getoption(struct camcontrol_opts *table, char *arg, 216216088Sken uint32_t *cmdnum, cam_argmask *argnum, 217118478Sjohan const char **subopt); 21889471Sjoerg#ifndef MINIMALISTIC 21939214Sgibbsstatic int getdevlist(struct cam_device *device); 220126514Sken#endif /* MINIMALISTIC */ 22139214Sgibbsstatic int getdevtree(void); 222126514Sken#ifndef MINIMALISTIC 22339214Sgibbsstatic int testunitready(struct cam_device *device, int retry_count, 22446581Sken int timeout, int quiet); 22539214Sgibbsstatic int scsistart(struct cam_device *device, int startstop, int loadeject, 22639214Sgibbs int retry_count, int timeout); 22739214Sgibbsstatic int scsiinquiry(struct cam_device *device, int retry_count, int timeout); 22839214Sgibbsstatic int scsiserial(struct cam_device *device, int retry_count, int timeout); 229198709Smavstatic int camxferrate(struct cam_device *device); 23089471Sjoerg#endif /* MINIMALISTIC */ 23146938Skenstatic int parse_btl(char *tstr, int *bus, int *target, int *lun, 232118478Sjohan cam_argmask *arglst); 23341962Smjacobstatic int dorescan_or_reset(int argc, char **argv, int rescan); 23441962Smjacobstatic int rescan_or_reset_bus(int bus, int rescan); 23541962Smjacobstatic int scanlun_or_reset_dev(int bus, int target, int lun, int scan); 23689471Sjoerg#ifndef MINIMALISTIC 23739214Sgibbsstatic int readdefects(struct cam_device *device, int argc, char **argv, 23839214Sgibbs char *combinedopt, int retry_count, int timeout); 23939214Sgibbsstatic void modepage(struct cam_device *device, int argc, char **argv, 24039214Sgibbs char *combinedopt, int retry_count, int timeout); 241214321Smavstatic int scsicmd(struct cam_device *device, int argc, char **argv, 24239214Sgibbs char *combinedopt, int retry_count, int timeout); 243216088Skenstatic int smpcmd(struct cam_device *device, int argc, char **argv, 244216088Sken char *combinedopt, int retry_count, int timeout); 245216088Skenstatic int smpreportgeneral(struct cam_device *device, int argc, char **argv, 246216088Sken char *combinedopt, int retry_count, int timeout); 247216088Skenstatic int smpphycontrol(struct cam_device *device, int argc, char **argv, 248216088Sken char *combinedopt, int retry_count, int timeout); 249216088Skenstatic int smpmaninfo(struct cam_device *device, int argc, char **argv, 250216088Sken char *combinedopt, int retry_count, int timeout); 251216088Skenstatic int getdevid(struct cam_devitem *item); 252216088Skenstatic int buildbusdevlist(struct cam_devlist *devlist); 253216088Skenstatic void freebusdevlist(struct cam_devlist *devlist); 254216088Skenstatic struct cam_devitem *findsasdevice(struct cam_devlist *devlist, 255216088Sken uint64_t sasaddr); 256216088Skenstatic int smpphylist(struct cam_device *device, int argc, char **argv, 257216088Sken char *combinedopt, int retry_count, int timeout); 25846581Skenstatic int tagcontrol(struct cam_device *device, int argc, char **argv, 25946581Sken char *combinedopt); 26046581Skenstatic void cts_print(struct cam_device *device, 26146581Sken struct ccb_trans_settings *cts); 26246581Skenstatic void cpi_print(struct ccb_pathinq *cpi); 26346581Skenstatic int get_cpi(struct cam_device *device, struct ccb_pathinq *cpi); 264196658Smavstatic int get_cgd(struct cam_device *device, struct ccb_getdev *cgd); 26546581Skenstatic int get_print_cts(struct cam_device *device, int user_settings, 26646581Sken int quiet, struct ccb_trans_settings *cts); 26746581Skenstatic int ratecontrol(struct cam_device *device, int retry_count, 26846581Sken int timeout, int argc, char **argv, char *combinedopt); 26960767Skenstatic int scsiformat(struct cam_device *device, int argc, char **argv, 27060767Sken char *combinedopt, int retry_count, int timeout); 271161506Skenstatic int scsireportluns(struct cam_device *device, int argc, char **argv, 272161506Sken char *combinedopt, int retry_count, int timeout); 273172093Skenstatic int scsireadcapacity(struct cam_device *device, int argc, char **argv, 274172093Sken char *combinedopt, int retry_count, int timeout); 275199079Smavstatic int atapm(struct cam_device *device, int argc, char **argv, 276199079Smav char *combinedopt, int retry_count, int timeout); 27789471Sjoerg#endif /* MINIMALISTIC */ 278199747Smav#ifndef min 279199747Smav#define min(a,b) (((a)<(b))?(a):(b)) 280199747Smav#endif 281199747Smav#ifndef max 282199747Smav#define max(a,b) (((a)>(b))?(a):(b)) 283199747Smav#endif 28439214Sgibbs 28539214Sgibbscamcontrol_optret 286216088Skengetoption(struct camcontrol_opts *table, char *arg, uint32_t *cmdnum, 287216088Sken cam_argmask *argnum, const char **subopt) 28839214Sgibbs{ 28939214Sgibbs struct camcontrol_opts *opts; 29039214Sgibbs int num_matches = 0; 29139214Sgibbs 292216088Sken for (opts = table; (opts != NULL) && (opts->optname != NULL); 29339214Sgibbs opts++) { 29439214Sgibbs if (strncmp(opts->optname, arg, strlen(arg)) == 0) { 295103092Smdodd *cmdnum = opts->cmdnum; 29639214Sgibbs *argnum = opts->argnum; 297118478Sjohan *subopt = opts->subopt; 29839214Sgibbs if (++num_matches > 1) 29939214Sgibbs return(CC_OR_AMBIGUOUS); 30039214Sgibbs } 30139214Sgibbs } 30239214Sgibbs 30339214Sgibbs if (num_matches > 0) 30439214Sgibbs return(CC_OR_FOUND); 30539214Sgibbs else 30639214Sgibbs return(CC_OR_NOT_FOUND); 30739214Sgibbs} 30839214Sgibbs 30989471Sjoerg#ifndef MINIMALISTIC 31039214Sgibbsstatic int 31139214Sgibbsgetdevlist(struct cam_device *device) 31239214Sgibbs{ 31339214Sgibbs union ccb *ccb; 31439214Sgibbs char status[32]; 31539214Sgibbs int error = 0; 31639214Sgibbs 31739214Sgibbs ccb = cam_getccb(device); 31839214Sgibbs 31939214Sgibbs ccb->ccb_h.func_code = XPT_GDEVLIST; 32039214Sgibbs ccb->ccb_h.flags = CAM_DIR_NONE; 32139214Sgibbs ccb->ccb_h.retry_count = 1; 32239214Sgibbs ccb->cgdl.index = 0; 32339214Sgibbs ccb->cgdl.status = CAM_GDEVLIST_MORE_DEVS; 32439214Sgibbs while (ccb->cgdl.status == CAM_GDEVLIST_MORE_DEVS) { 32539214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 32639214Sgibbs perror("error getting device list"); 32739214Sgibbs cam_freeccb(ccb); 32839214Sgibbs return(1); 32939214Sgibbs } 33039214Sgibbs 33139214Sgibbs status[0] = '\0'; 33239214Sgibbs 33339214Sgibbs switch (ccb->cgdl.status) { 33439214Sgibbs case CAM_GDEVLIST_MORE_DEVS: 33539214Sgibbs strcpy(status, "MORE"); 33639214Sgibbs break; 33739214Sgibbs case CAM_GDEVLIST_LAST_DEVICE: 33839214Sgibbs strcpy(status, "LAST"); 33939214Sgibbs break; 34039214Sgibbs case CAM_GDEVLIST_LIST_CHANGED: 34139214Sgibbs strcpy(status, "CHANGED"); 34239214Sgibbs break; 34339214Sgibbs case CAM_GDEVLIST_ERROR: 34439214Sgibbs strcpy(status, "ERROR"); 34539214Sgibbs error = 1; 34639214Sgibbs break; 34739214Sgibbs } 34839214Sgibbs 34939214Sgibbs fprintf(stdout, "%s%d: generation: %d index: %d status: %s\n", 35039214Sgibbs ccb->cgdl.periph_name, 35139214Sgibbs ccb->cgdl.unit_number, 35239214Sgibbs ccb->cgdl.generation, 35339214Sgibbs ccb->cgdl.index, 35439214Sgibbs status); 35539214Sgibbs 35639214Sgibbs /* 35739214Sgibbs * If the list has changed, we need to start over from the 35839214Sgibbs * beginning. 35939214Sgibbs */ 36039214Sgibbs if (ccb->cgdl.status == CAM_GDEVLIST_LIST_CHANGED) 36139214Sgibbs ccb->cgdl.index = 0; 36239214Sgibbs } 36339214Sgibbs 36439214Sgibbs cam_freeccb(ccb); 36539214Sgibbs 36639214Sgibbs return(error); 36739214Sgibbs} 36889521Sjoerg#endif /* MINIMALISTIC */ 36939214Sgibbs 37039214Sgibbsstatic int 37139214Sgibbsgetdevtree(void) 37239214Sgibbs{ 37339214Sgibbs union ccb ccb; 374102192Sjohan int bufsize, fd; 375102192Sjohan unsigned int i; 37639214Sgibbs int need_close = 0; 37739214Sgibbs int error = 0; 37846581Sken int skip_device = 0; 37939214Sgibbs 38039214Sgibbs if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) { 38139214Sgibbs warn("couldn't open %s", XPT_DEVICE); 38239214Sgibbs return(1); 38339214Sgibbs } 38439214Sgibbs 385126514Sken bzero(&ccb, sizeof(union ccb)); 38639214Sgibbs 387126514Sken ccb.ccb_h.path_id = CAM_XPT_PATH_ID; 388126514Sken ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; 389126514Sken ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; 390126514Sken 39139214Sgibbs ccb.ccb_h.func_code = XPT_DEV_MATCH; 39239214Sgibbs bufsize = sizeof(struct dev_match_result) * 100; 39339214Sgibbs ccb.cdm.match_buf_len = bufsize; 39439214Sgibbs ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize); 39569471Sjedgar if (ccb.cdm.matches == NULL) { 39669471Sjedgar warnx("can't malloc memory for matches"); 39769471Sjedgar close(fd); 39869471Sjedgar return(1); 39969471Sjedgar } 40039214Sgibbs ccb.cdm.num_matches = 0; 40139214Sgibbs 40239214Sgibbs /* 40339214Sgibbs * We fetch all nodes, since we display most of them in the default 40439214Sgibbs * case, and all in the verbose case. 40539214Sgibbs */ 40639214Sgibbs ccb.cdm.num_patterns = 0; 40739214Sgibbs ccb.cdm.pattern_buf_len = 0; 40839214Sgibbs 40939214Sgibbs /* 41039214Sgibbs * We do the ioctl multiple times if necessary, in case there are 41139214Sgibbs * more than 100 nodes in the EDT. 41239214Sgibbs */ 41339214Sgibbs do { 41439214Sgibbs if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 41539214Sgibbs warn("error sending CAMIOCOMMAND ioctl"); 41639214Sgibbs error = 1; 41739214Sgibbs break; 41839214Sgibbs } 41939214Sgibbs 42039214Sgibbs if ((ccb.ccb_h.status != CAM_REQ_CMP) 42139214Sgibbs || ((ccb.cdm.status != CAM_DEV_MATCH_LAST) 42239214Sgibbs && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { 42389515Sken warnx("got CAM error %#x, CDM error %d\n", 42489515Sken ccb.ccb_h.status, ccb.cdm.status); 42539214Sgibbs error = 1; 42639214Sgibbs break; 42739214Sgibbs } 42839214Sgibbs 42939214Sgibbs for (i = 0; i < ccb.cdm.num_matches; i++) { 43089515Sken switch (ccb.cdm.matches[i].type) { 43139214Sgibbs case DEV_MATCH_BUS: { 43239214Sgibbs struct bus_match_result *bus_result; 43339214Sgibbs 43439214Sgibbs /* 43539214Sgibbs * Only print the bus information if the 43639214Sgibbs * user turns on the verbose flag. 43739214Sgibbs */ 43839214Sgibbs if ((arglist & CAM_ARG_VERBOSE) == 0) 43939214Sgibbs break; 44039214Sgibbs 44139214Sgibbs bus_result = 44239214Sgibbs &ccb.cdm.matches[i].result.bus_result; 44339214Sgibbs 44439214Sgibbs if (need_close) { 44539214Sgibbs fprintf(stdout, ")\n"); 44639214Sgibbs need_close = 0; 44739214Sgibbs } 44839214Sgibbs 44939214Sgibbs fprintf(stdout, "scbus%d on %s%d bus %d:\n", 45039214Sgibbs bus_result->path_id, 45139214Sgibbs bus_result->dev_name, 45239214Sgibbs bus_result->unit_number, 45339214Sgibbs bus_result->bus_id); 45439214Sgibbs break; 45539214Sgibbs } 45639214Sgibbs case DEV_MATCH_DEVICE: { 45739214Sgibbs struct device_match_result *dev_result; 45839214Sgibbs char vendor[16], product[48], revision[16]; 459235897Smav char fw[5], tmpstr[256]; 46039214Sgibbs 46139214Sgibbs dev_result = 46239214Sgibbs &ccb.cdm.matches[i].result.device_result; 46339214Sgibbs 46446581Sken if ((dev_result->flags 46546581Sken & DEV_RESULT_UNCONFIGURED) 46646581Sken && ((arglist & CAM_ARG_VERBOSE) == 0)) { 46746581Sken skip_device = 1; 46846581Sken break; 46946581Sken } else 47046581Sken skip_device = 0; 47146581Sken 472195534Sscottl if (dev_result->protocol == PROTO_SCSI) { 473195534Sscottl cam_strvis(vendor, dev_result->inq_data.vendor, 47439214Sgibbs sizeof(dev_result->inq_data.vendor), 47539214Sgibbs sizeof(vendor)); 476195534Sscottl cam_strvis(product, 47739214Sgibbs dev_result->inq_data.product, 47839214Sgibbs sizeof(dev_result->inq_data.product), 47939214Sgibbs sizeof(product)); 480195534Sscottl cam_strvis(revision, 48139214Sgibbs dev_result->inq_data.revision, 48239214Sgibbs sizeof(dev_result->inq_data.revision), 48339214Sgibbs sizeof(revision)); 484195534Sscottl sprintf(tmpstr, "<%s %s %s>", vendor, product, 48539214Sgibbs revision); 486195534Sscottl } else if (dev_result->protocol == PROTO_ATA || 487195534Sscottl dev_result->protocol == PROTO_SATAPM) { 488195534Sscottl cam_strvis(product, 489195534Sscottl dev_result->ident_data.model, 490195534Sscottl sizeof(dev_result->ident_data.model), 491195534Sscottl sizeof(product)); 492195534Sscottl cam_strvis(revision, 493195534Sscottl dev_result->ident_data.revision, 494195534Sscottl sizeof(dev_result->ident_data.revision), 495195534Sscottl sizeof(revision)); 496195534Sscottl sprintf(tmpstr, "<%s %s>", product, 497195534Sscottl revision); 498235897Smav } else if (dev_result->protocol == PROTO_SEMB) { 499235897Smav struct sep_identify_data *sid; 500235897Smav 501235897Smav sid = (struct sep_identify_data *) 502235897Smav &dev_result->ident_data; 503235897Smav cam_strvis(vendor, sid->vendor_id, 504235897Smav sizeof(sid->vendor_id), 505235897Smav sizeof(vendor)); 506235897Smav cam_strvis(product, sid->product_id, 507235897Smav sizeof(sid->product_id), 508235897Smav sizeof(product)); 509235897Smav cam_strvis(revision, sid->product_rev, 510235897Smav sizeof(sid->product_rev), 511235897Smav sizeof(revision)); 512235897Smav cam_strvis(fw, sid->firmware_rev, 513235897Smav sizeof(sid->firmware_rev), 514235897Smav sizeof(fw)); 515235897Smav sprintf(tmpstr, "<%s %s %s %s>", 516235897Smav vendor, product, revision, fw); 517195534Sscottl } else { 518195534Sscottl sprintf(tmpstr, "<>"); 519195534Sscottl } 52039214Sgibbs if (need_close) { 52139214Sgibbs fprintf(stdout, ")\n"); 52239214Sgibbs need_close = 0; 52339214Sgibbs } 52439214Sgibbs 52539214Sgibbs fprintf(stdout, "%-33s at scbus%d " 52639214Sgibbs "target %d lun %d (", 52739214Sgibbs tmpstr, 52839214Sgibbs dev_result->path_id, 52939214Sgibbs dev_result->target_id, 53039214Sgibbs dev_result->target_lun); 53142647Sgibbs 53242647Sgibbs need_close = 1; 53342647Sgibbs 53439214Sgibbs break; 53539214Sgibbs } 53639214Sgibbs case DEV_MATCH_PERIPH: { 53739214Sgibbs struct periph_match_result *periph_result; 53839214Sgibbs 53939214Sgibbs periph_result = 54039214Sgibbs &ccb.cdm.matches[i].result.periph_result; 54139214Sgibbs 54246581Sken if (skip_device != 0) 54346581Sken break; 54446581Sken 54542647Sgibbs if (need_close > 1) 54639214Sgibbs fprintf(stdout, ","); 54739214Sgibbs 54839214Sgibbs fprintf(stdout, "%s%d", 54939214Sgibbs periph_result->periph_name, 55039214Sgibbs periph_result->unit_number); 55139214Sgibbs 55242647Sgibbs need_close++; 55339214Sgibbs break; 55439214Sgibbs } 55539214Sgibbs default: 55639214Sgibbs fprintf(stdout, "unknown match type\n"); 55739214Sgibbs break; 55839214Sgibbs } 55939214Sgibbs } 56039214Sgibbs 56139214Sgibbs } while ((ccb.ccb_h.status == CAM_REQ_CMP) 56239214Sgibbs && (ccb.cdm.status == CAM_DEV_MATCH_MORE)); 56339214Sgibbs 56439214Sgibbs if (need_close) 56539214Sgibbs fprintf(stdout, ")\n"); 56639214Sgibbs 56739214Sgibbs close(fd); 56839214Sgibbs 56939214Sgibbs return(error); 57039214Sgibbs} 57139214Sgibbs 57289521Sjoerg#ifndef MINIMALISTIC 57339214Sgibbsstatic int 57446581Skentestunitready(struct cam_device *device, int retry_count, int timeout, 57546581Sken int quiet) 57639214Sgibbs{ 57739214Sgibbs int error = 0; 57839214Sgibbs union ccb *ccb; 57939214Sgibbs 58039214Sgibbs ccb = cam_getccb(device); 58139214Sgibbs 58239214Sgibbs scsi_test_unit_ready(&ccb->csio, 58339214Sgibbs /* retries */ retry_count, 58439214Sgibbs /* cbfcnp */ NULL, 58539214Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 58639214Sgibbs /* sense_len */ SSD_FULL_SIZE, 58739214Sgibbs /* timeout */ timeout ? timeout : 5000); 58839214Sgibbs 58939214Sgibbs /* Disable freezing the device queue */ 59039214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 59139214Sgibbs 59239214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 59339214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 59439214Sgibbs 59539214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 59646581Sken if (quiet == 0) 59746581Sken perror("error sending test unit ready"); 59839214Sgibbs 59939214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 60074840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 60174840Sken CAM_EPF_ALL, stderr); 60239214Sgibbs } 60339214Sgibbs 60439214Sgibbs cam_freeccb(ccb); 60539214Sgibbs return(1); 60639214Sgibbs } 60739214Sgibbs 60846581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 60946581Sken if (quiet == 0) 61046581Sken fprintf(stdout, "Unit is ready\n"); 61146581Sken } else { 61246581Sken if (quiet == 0) 61346581Sken fprintf(stdout, "Unit is not ready\n"); 61439214Sgibbs error = 1; 61539214Sgibbs 61639214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 61774840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 61874840Sken CAM_EPF_ALL, stderr); 61939214Sgibbs } 62039214Sgibbs } 62139214Sgibbs 62239214Sgibbs cam_freeccb(ccb); 62339214Sgibbs 62439214Sgibbs return(error); 62539214Sgibbs} 62639214Sgibbs 62739214Sgibbsstatic int 62839214Sgibbsscsistart(struct cam_device *device, int startstop, int loadeject, 62939214Sgibbs int retry_count, int timeout) 63039214Sgibbs{ 63139214Sgibbs union ccb *ccb; 63239214Sgibbs int error = 0; 63339214Sgibbs 63439214Sgibbs ccb = cam_getccb(device); 63539214Sgibbs 63640319Sken /* 63740319Sken * If we're stopping, send an ordered tag so the drive in question 63840319Sken * will finish any previously queued writes before stopping. If 63940319Sken * the device isn't capable of tagged queueing, or if tagged 64040319Sken * queueing is turned off, the tag action is a no-op. 64140319Sken */ 64239214Sgibbs scsi_start_stop(&ccb->csio, 64339214Sgibbs /* retries */ retry_count, 64439214Sgibbs /* cbfcnp */ NULL, 64540319Sken /* tag_action */ startstop ? MSG_SIMPLE_Q_TAG : 64640319Sken MSG_ORDERED_Q_TAG, 64739214Sgibbs /* start/stop */ startstop, 64839214Sgibbs /* load_eject */ loadeject, 64939214Sgibbs /* immediate */ 0, 65039214Sgibbs /* sense_len */ SSD_FULL_SIZE, 65139214Sgibbs /* timeout */ timeout ? timeout : 120000); 65239214Sgibbs 65339214Sgibbs /* Disable freezing the device queue */ 65439214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 65539214Sgibbs 65639214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 65739214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 65839214Sgibbs 65939214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 66039214Sgibbs perror("error sending start unit"); 66139214Sgibbs 66239214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 66374840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 66474840Sken CAM_EPF_ALL, stderr); 66539214Sgibbs } 66639214Sgibbs 66739214Sgibbs cam_freeccb(ccb); 66839214Sgibbs return(1); 66939214Sgibbs } 67039214Sgibbs 67139214Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 67239214Sgibbs if (startstop) { 67339214Sgibbs fprintf(stdout, "Unit started successfully"); 67439214Sgibbs if (loadeject) 67539214Sgibbs fprintf(stdout,", Media loaded\n"); 67639214Sgibbs else 67739214Sgibbs fprintf(stdout,"\n"); 67839214Sgibbs } else { 67939214Sgibbs fprintf(stdout, "Unit stopped successfully"); 68039214Sgibbs if (loadeject) 68139214Sgibbs fprintf(stdout, ", Media ejected\n"); 68239214Sgibbs else 68339214Sgibbs fprintf(stdout, "\n"); 68439214Sgibbs } 68539214Sgibbs else { 68639214Sgibbs error = 1; 68739214Sgibbs if (startstop) 68839214Sgibbs fprintf(stdout, 68939214Sgibbs "Error received from start unit command\n"); 69039214Sgibbs else 69139214Sgibbs fprintf(stdout, 69239214Sgibbs "Error received from stop unit command\n"); 693214321Smav 69439214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 69574840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 69674840Sken CAM_EPF_ALL, stderr); 69739214Sgibbs } 69839214Sgibbs } 69939214Sgibbs 70039214Sgibbs cam_freeccb(ccb); 70139214Sgibbs 70239214Sgibbs return(error); 70339214Sgibbs} 70439214Sgibbs 705227961Semasteint 70639214Sgibbsscsidoinquiry(struct cam_device *device, int argc, char **argv, 70739214Sgibbs char *combinedopt, int retry_count, int timeout) 70839214Sgibbs{ 70939214Sgibbs int c; 71039214Sgibbs int error = 0; 71139214Sgibbs 71239214Sgibbs while ((c = getopt(argc, argv, combinedopt)) != -1) { 71339214Sgibbs switch(c) { 71439214Sgibbs case 'D': 71539214Sgibbs arglist |= CAM_ARG_GET_STDINQ; 71639214Sgibbs break; 71739214Sgibbs case 'R': 71839214Sgibbs arglist |= CAM_ARG_GET_XFERRATE; 71939214Sgibbs break; 72039214Sgibbs case 'S': 72139214Sgibbs arglist |= CAM_ARG_GET_SERIAL; 72239214Sgibbs break; 72339214Sgibbs default: 72439214Sgibbs break; 72539214Sgibbs } 72639214Sgibbs } 72739214Sgibbs 72839214Sgibbs /* 72939214Sgibbs * If the user didn't specify any inquiry options, he wants all of 73039214Sgibbs * them. 73139214Sgibbs */ 73239214Sgibbs if ((arglist & CAM_ARG_INQ_MASK) == 0) 73339214Sgibbs arglist |= CAM_ARG_INQ_MASK; 73439214Sgibbs 73539214Sgibbs if (arglist & CAM_ARG_GET_STDINQ) 73639214Sgibbs error = scsiinquiry(device, retry_count, timeout); 73739214Sgibbs 73839214Sgibbs if (error != 0) 73939214Sgibbs return(error); 74039214Sgibbs 74139214Sgibbs if (arglist & CAM_ARG_GET_SERIAL) 74239214Sgibbs scsiserial(device, retry_count, timeout); 74339214Sgibbs 74439214Sgibbs if (error != 0) 74539214Sgibbs return(error); 74639214Sgibbs 74739214Sgibbs if (arglist & CAM_ARG_GET_XFERRATE) 748198709Smav error = camxferrate(device); 74939214Sgibbs 75039214Sgibbs return(error); 75139214Sgibbs} 75239214Sgibbs 75339214Sgibbsstatic int 75439214Sgibbsscsiinquiry(struct cam_device *device, int retry_count, int timeout) 75539214Sgibbs{ 75639214Sgibbs union ccb *ccb; 75739214Sgibbs struct scsi_inquiry_data *inq_buf; 75839214Sgibbs int error = 0; 759214321Smav 76039214Sgibbs ccb = cam_getccb(device); 76139214Sgibbs 76239214Sgibbs if (ccb == NULL) { 76339214Sgibbs warnx("couldn't allocate CCB"); 76439214Sgibbs return(1); 76539214Sgibbs } 76639214Sgibbs 76739214Sgibbs /* cam_getccb cleans up the header, caller has to zero the payload */ 76846581Sken bzero(&(&ccb->ccb_h)[1], 76946581Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 77039214Sgibbs 77139214Sgibbs inq_buf = (struct scsi_inquiry_data *)malloc( 77239214Sgibbs sizeof(struct scsi_inquiry_data)); 77339214Sgibbs 77439214Sgibbs if (inq_buf == NULL) { 77539214Sgibbs cam_freeccb(ccb); 77639214Sgibbs warnx("can't malloc memory for inquiry\n"); 77739214Sgibbs return(1); 77839214Sgibbs } 77939214Sgibbs bzero(inq_buf, sizeof(*inq_buf)); 78039214Sgibbs 78157349Sken /* 78257349Sken * Note that although the size of the inquiry buffer is the full 78357349Sken * 256 bytes specified in the SCSI spec, we only tell the device 78457349Sken * that we have allocated SHORT_INQUIRY_LENGTH bytes. There are 78557349Sken * two reasons for this: 78657349Sken * 78757349Sken * - The SCSI spec says that when a length field is only 1 byte, 78857349Sken * a value of 0 will be interpreted as 256. Therefore 78957349Sken * scsi_inquiry() will convert an inq_len (which is passed in as 79057349Sken * a u_int32_t, but the field in the CDB is only 1 byte) of 256 79157349Sken * to 0. Evidently, very few devices meet the spec in that 792214321Smav * regard. Some devices, like many Seagate disks, take the 0 as 79357349Sken * 0, and don't return any data. One Pioneer DVD-R drive 79457349Sken * returns more data than the command asked for. 79557349Sken * 79657349Sken * So, since there are numerous devices that just don't work 79757349Sken * right with the full inquiry size, we don't send the full size. 798214321Smav * 79957349Sken * - The second reason not to use the full inquiry data length is 80057349Sken * that we don't need it here. The only reason we issue a 80157349Sken * standard inquiry is to get the vendor name, device name, 80257349Sken * and revision so scsi_print_inquiry() can print them. 80357349Sken * 80457349Sken * If, at some point in the future, more inquiry data is needed for 80557349Sken * some reason, this code should use a procedure similar to the 80657349Sken * probe code. i.e., issue a short inquiry, and determine from 80757349Sken * the additional length passed back from the device how much 80857349Sken * inquiry data the device supports. Once the amount the device 80957349Sken * supports is determined, issue an inquiry for that amount and no 81057349Sken * more. 81157349Sken * 81257349Sken * KDM, 2/18/2000 81357349Sken */ 81439214Sgibbs scsi_inquiry(&ccb->csio, 81539214Sgibbs /* retries */ retry_count, 81639214Sgibbs /* cbfcnp */ NULL, 81739214Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 81839214Sgibbs /* inq_buf */ (u_int8_t *)inq_buf, 81957349Sken /* inq_len */ SHORT_INQUIRY_LENGTH, 82039214Sgibbs /* evpd */ 0, 82139214Sgibbs /* page_code */ 0, 82239214Sgibbs /* sense_len */ SSD_FULL_SIZE, 82339214Sgibbs /* timeout */ timeout ? timeout : 5000); 82439214Sgibbs 82539214Sgibbs /* Disable freezing the device queue */ 82639214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 82739214Sgibbs 82839214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 82939214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 83039214Sgibbs 83139214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 83239214Sgibbs perror("error sending SCSI inquiry"); 83339214Sgibbs 83439214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 83574840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 83674840Sken CAM_EPF_ALL, stderr); 83739214Sgibbs } 83839214Sgibbs 83939214Sgibbs cam_freeccb(ccb); 84039214Sgibbs return(1); 84139214Sgibbs } 84239214Sgibbs 84339214Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 84439214Sgibbs error = 1; 84539214Sgibbs 84639214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 84774840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 84874840Sken CAM_EPF_ALL, stderr); 84939214Sgibbs } 85039214Sgibbs } 85139214Sgibbs 85239214Sgibbs cam_freeccb(ccb); 85339214Sgibbs 85439214Sgibbs if (error != 0) { 85539214Sgibbs free(inq_buf); 85639214Sgibbs return(error); 85739214Sgibbs } 85839214Sgibbs 85946581Sken fprintf(stdout, "%s%d: ", device->device_name, 86046581Sken device->dev_unit_num); 86139214Sgibbs scsi_print_inquiry(inq_buf); 86239214Sgibbs 86339214Sgibbs free(inq_buf); 86439214Sgibbs 86539214Sgibbs return(0); 86639214Sgibbs} 86739214Sgibbs 86839214Sgibbsstatic int 86939214Sgibbsscsiserial(struct cam_device *device, int retry_count, int timeout) 87039214Sgibbs{ 87139214Sgibbs union ccb *ccb; 87239214Sgibbs struct scsi_vpd_unit_serial_number *serial_buf; 87339214Sgibbs char serial_num[SVPD_SERIAL_NUM_SIZE + 1]; 87439214Sgibbs int error = 0; 87539214Sgibbs 87639214Sgibbs ccb = cam_getccb(device); 87739214Sgibbs 87839214Sgibbs if (ccb == NULL) { 87939214Sgibbs warnx("couldn't allocate CCB"); 88039214Sgibbs return(1); 88139214Sgibbs } 88239214Sgibbs 88339214Sgibbs /* cam_getccb cleans up the header, caller has to zero the payload */ 88446581Sken bzero(&(&ccb->ccb_h)[1], 88546581Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 88639214Sgibbs 88739214Sgibbs serial_buf = (struct scsi_vpd_unit_serial_number *) 88839214Sgibbs malloc(sizeof(*serial_buf)); 88939214Sgibbs 89039214Sgibbs if (serial_buf == NULL) { 89139214Sgibbs cam_freeccb(ccb); 89239214Sgibbs warnx("can't malloc memory for serial number"); 89339214Sgibbs return(1); 89439214Sgibbs } 89539214Sgibbs 89639214Sgibbs scsi_inquiry(&ccb->csio, 89739214Sgibbs /*retries*/ retry_count, 89839214Sgibbs /*cbfcnp*/ NULL, 89939214Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 90039214Sgibbs /* inq_buf */ (u_int8_t *)serial_buf, 90139214Sgibbs /* inq_len */ sizeof(*serial_buf), 90239214Sgibbs /* evpd */ 1, 90339214Sgibbs /* page_code */ SVPD_UNIT_SERIAL_NUMBER, 90439214Sgibbs /* sense_len */ SSD_FULL_SIZE, 90539214Sgibbs /* timeout */ timeout ? timeout : 5000); 90639214Sgibbs 90739214Sgibbs /* Disable freezing the device queue */ 90839214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 90939214Sgibbs 91039214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 91139214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 91239214Sgibbs 91339214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 91439214Sgibbs warn("error getting serial number"); 91539214Sgibbs 91639214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 91774840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 91874840Sken CAM_EPF_ALL, stderr); 91939214Sgibbs } 92039214Sgibbs 92139214Sgibbs cam_freeccb(ccb); 92239214Sgibbs free(serial_buf); 92339214Sgibbs return(1); 92439214Sgibbs } 92539214Sgibbs 92639214Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 92739214Sgibbs error = 1; 92839214Sgibbs 92939214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 93074840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 93174840Sken CAM_EPF_ALL, stderr); 93239214Sgibbs } 93339214Sgibbs } 93439214Sgibbs 93539214Sgibbs cam_freeccb(ccb); 93639214Sgibbs 93739214Sgibbs if (error != 0) { 93839214Sgibbs free(serial_buf); 93939214Sgibbs return(error); 94039214Sgibbs } 94139214Sgibbs 94239214Sgibbs bcopy(serial_buf->serial_num, serial_num, serial_buf->length); 94339214Sgibbs serial_num[serial_buf->length] = '\0'; 94439214Sgibbs 94546581Sken if ((arglist & CAM_ARG_GET_STDINQ) 94646581Sken || (arglist & CAM_ARG_GET_XFERRATE)) 94746581Sken fprintf(stdout, "%s%d: Serial Number ", 94846581Sken device->device_name, device->dev_unit_num); 94939214Sgibbs 95039214Sgibbs fprintf(stdout, "%.60s\n", serial_num); 95139214Sgibbs 95239214Sgibbs free(serial_buf); 95339214Sgibbs 95439214Sgibbs return(0); 95539214Sgibbs} 95639214Sgibbs 95739214Sgibbsstatic int 958198709Smavcamxferrate(struct cam_device *device) 95939214Sgibbs{ 960198709Smav struct ccb_pathinq cpi; 961163896Smjacob u_int32_t freq = 0; 962163896Smjacob u_int32_t speed = 0; 96346581Sken union ccb *ccb; 96446581Sken u_int mb; 96546581Sken int retval = 0; 96639214Sgibbs 967198709Smav if ((retval = get_cpi(device, &cpi)) != 0) 968198709Smav return (1); 969198709Smav 97046581Sken ccb = cam_getccb(device); 97146581Sken 97246581Sken if (ccb == NULL) { 97346581Sken warnx("couldn't allocate CCB"); 97446581Sken return(1); 97546581Sken } 97646581Sken 97746581Sken bzero(&(&ccb->ccb_h)[1], 97846581Sken sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr)); 97946581Sken 98046581Sken ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 981163896Smjacob ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS; 98246581Sken 98346581Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 98446581Sken || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 98569254Skris const char error_string[] = "error getting transfer settings"; 98646581Sken 98746581Sken if (retval < 0) 98846581Sken warn(error_string); 98946581Sken else 99046581Sken warnx(error_string); 99146581Sken 99246581Sken if (arglist & CAM_ARG_VERBOSE) 99374840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 99474840Sken CAM_EPF_ALL, stderr); 99546581Sken 99646581Sken retval = 1; 99746581Sken 99846581Sken goto xferrate_bailout; 99946581Sken 100046581Sken } 100146581Sken 1002198709Smav speed = cpi.base_transfer_speed; 1003198709Smav freq = 0; 1004163896Smjacob if (ccb->cts.transport == XPORT_SPI) { 1005163896Smjacob struct ccb_trans_settings_spi *spi = 1006163896Smjacob &ccb->cts.xport_specific.spi; 1007163896Smjacob 1008163896Smjacob if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) { 1009163896Smjacob freq = scsi_calc_syncsrate(spi->sync_period); 1010163896Smjacob speed = freq; 1011163896Smjacob } 1012163896Smjacob if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 1013163896Smjacob speed *= (0x01 << spi->bus_width); 1014163896Smjacob } 1015198709Smav } else if (ccb->cts.transport == XPORT_FC) { 1016198709Smav struct ccb_trans_settings_fc *fc = 1017198709Smav &ccb->cts.xport_specific.fc; 1018163896Smjacob 1019198709Smav if (fc->valid & CTS_FC_VALID_SPEED) 1020198709Smav speed = fc->bitrate; 1021198709Smav } else if (ccb->cts.transport == XPORT_SAS) { 1022198709Smav struct ccb_trans_settings_sas *sas = 1023198709Smav &ccb->cts.xport_specific.sas; 1024163896Smjacob 1025198709Smav if (sas->valid & CTS_SAS_VALID_SPEED) 1026198709Smav speed = sas->bitrate; 1027199747Smav } else if (ccb->cts.transport == XPORT_ATA) { 1028236437Smav struct ccb_trans_settings_pata *pata = 1029199747Smav &ccb->cts.xport_specific.ata; 1030199747Smav 1031236437Smav if (pata->valid & CTS_ATA_VALID_MODE) 1032236437Smav speed = ata_mode2speed(pata->mode); 1033198709Smav } else if (ccb->cts.transport == XPORT_SATA) { 1034199747Smav struct ccb_trans_settings_sata *sata = 1035198709Smav &ccb->cts.xport_specific.sata; 1036163896Smjacob 1037199747Smav if (sata->valid & CTS_SATA_VALID_REVISION) 1038199747Smav speed = ata_revision2speed(sata->revision); 1039198709Smav } 1040198709Smav 1041198709Smav mb = speed / 1000; 1042198709Smav if (mb > 0) { 1043199747Smav fprintf(stdout, "%s%d: %d.%03dMB/s transfers", 1044198709Smav device->device_name, device->dev_unit_num, 1045198709Smav mb, speed % 1000); 1046198709Smav } else { 1047199747Smav fprintf(stdout, "%s%d: %dKB/s transfers", 1048198709Smav device->device_name, device->dev_unit_num, 1049198709Smav speed); 1050198709Smav } 1051198709Smav 1052198709Smav if (ccb->cts.transport == XPORT_SPI) { 1053198709Smav struct ccb_trans_settings_spi *spi = 1054198709Smav &ccb->cts.xport_specific.spi; 1055198709Smav 1056163896Smjacob if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0) 1057163896Smjacob && (spi->sync_offset != 0)) 1058199747Smav fprintf(stdout, " (%d.%03dMHz, offset %d", freq / 1000, 1059163896Smjacob freq % 1000, spi->sync_offset); 1060163896Smjacob 1061163896Smjacob if (((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) 1062163896Smjacob && (spi->bus_width > 0)) { 1063163896Smjacob if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0) 1064163896Smjacob && (spi->sync_offset != 0)) { 1065163896Smjacob fprintf(stdout, ", "); 1066163896Smjacob } else { 1067163896Smjacob fprintf(stdout, " ("); 1068163896Smjacob } 1069163896Smjacob fprintf(stdout, "%dbit)", 8 * (0x01 << spi->bus_width)); 1070163896Smjacob } else if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0) 1071163896Smjacob && (spi->sync_offset != 0)) { 1072163896Smjacob fprintf(stdout, ")"); 1073163896Smjacob } 1074198709Smav } else if (ccb->cts.transport == XPORT_ATA) { 1075236437Smav struct ccb_trans_settings_pata *pata = 1076198709Smav &ccb->cts.xport_specific.ata; 107746581Sken 1078199747Smav printf(" ("); 1079236437Smav if (pata->valid & CTS_ATA_VALID_MODE) 1080236437Smav printf("%s, ", ata_mode2string(pata->mode)); 1081236437Smav if ((pata->valid & CTS_ATA_VALID_ATAPI) && pata->atapi != 0) 1082236437Smav printf("ATAPI %dbytes, ", pata->atapi); 1083236437Smav if (pata->valid & CTS_ATA_VALID_BYTECOUNT) 1084236437Smav printf("PIO %dbytes", pata->bytecount); 1085199747Smav printf(")"); 1086198709Smav } else if (ccb->cts.transport == XPORT_SATA) { 1087198709Smav struct ccb_trans_settings_sata *sata = 1088198709Smav &ccb->cts.xport_specific.sata; 108946581Sken 1090199747Smav printf(" ("); 1091199747Smav if (sata->valid & CTS_SATA_VALID_REVISION) 1092199747Smav printf("SATA %d.x, ", sata->revision); 1093204195Smav else 1094204195Smav printf("SATA, "); 1095199747Smav if (sata->valid & CTS_SATA_VALID_MODE) 1096199747Smav printf("%s, ", ata_mode2string(sata->mode)); 1097203376Smav if ((sata->valid & CTS_SATA_VALID_ATAPI) && sata->atapi != 0) 1098203376Smav printf("ATAPI %dbytes, ", sata->atapi); 1099199747Smav if (sata->valid & CTS_SATA_VALID_BYTECOUNT) 1100203376Smav printf("PIO %dbytes", sata->bytecount); 1101199747Smav printf(")"); 1102163896Smjacob } 110339214Sgibbs 1104163896Smjacob if (ccb->cts.protocol == PROTO_SCSI) { 1105163896Smjacob struct ccb_trans_settings_scsi *scsi = 1106163896Smjacob &ccb->cts.proto_specific.scsi; 1107163896Smjacob if (scsi->valid & CTS_SCSI_VALID_TQ) { 1108164842Smjacob if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) { 1109163896Smjacob fprintf(stdout, ", Command Queueing Enabled"); 1110164842Smjacob } 111146581Sken } 111246581Sken } 111346581Sken 111439214Sgibbs fprintf(stdout, "\n"); 111539214Sgibbs 111646581Skenxferrate_bailout: 111746581Sken 111846581Sken cam_freeccb(ccb); 111946581Sken 112046581Sken return(retval); 112139214Sgibbs} 1122195534Sscottl 1123195534Sscottlstatic void 1124195534Sscottlatacapprint(struct ata_params *parm) 1125195534Sscottl{ 1126195534Sscottl u_int32_t lbasize = (u_int32_t)parm->lba_size_1 | 1127195534Sscottl ((u_int32_t)parm->lba_size_2 << 16); 1128195534Sscottl 1129195534Sscottl u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) | 1130195534Sscottl ((u_int64_t)parm->lba_size48_2 << 16) | 1131195534Sscottl ((u_int64_t)parm->lba_size48_3 << 32) | 1132195534Sscottl ((u_int64_t)parm->lba_size48_4 << 48); 1133195534Sscottl 1134195534Sscottl printf("\n"); 1135196658Smav printf("protocol "); 1136196658Smav printf("ATA/ATAPI-%d", ata_version(parm->version_major)); 1137195534Sscottl if (parm->satacapabilities && parm->satacapabilities != 0xffff) { 1138197545Smav if (parm->satacapabilities & ATA_SATA_GEN3) 1139197545Smav printf(" SATA 3.x\n"); 1140197545Smav else if (parm->satacapabilities & ATA_SATA_GEN2) 1141196658Smav printf(" SATA 2.x\n"); 1142195534Sscottl else if (parm->satacapabilities & ATA_SATA_GEN1) 1143196658Smav printf(" SATA 1.x\n"); 1144195534Sscottl else 1145197545Smav printf(" SATA\n"); 1146195534Sscottl } 1147195534Sscottl else 1148196658Smav printf("\n"); 1149195534Sscottl printf("device model %.40s\n", parm->model); 1150197545Smav printf("firmware revision %.8s\n", parm->revision); 1151195534Sscottl printf("serial number %.20s\n", parm->serial); 1152197545Smav if (parm->enabled.extension & ATA_SUPPORT_64BITWWN) { 1153225018Smav printf("WWN %04x%04x%04x%04x\n", 1154197545Smav parm->wwn[0], parm->wwn[1], parm->wwn[2], parm->wwn[3]); 1155197545Smav } 1156197545Smav if (parm->enabled.extension & ATA_SUPPORT_MEDIASN) { 1157197545Smav printf("media serial number %.30s\n", 1158197545Smav parm->media_serial); 1159197545Smav } 1160195534Sscottl 1161195534Sscottl printf("cylinders %d\n", parm->cylinders); 1162195534Sscottl printf("heads %d\n", parm->heads); 1163195534Sscottl printf("sectors/track %d\n", parm->sectors); 1164198897Smav printf("sector size logical %u, physical %lu, offset %lu\n", 1165198897Smav ata_logical_sector_size(parm), 1166198897Smav (unsigned long)ata_physical_sector_size(parm), 1167198897Smav (unsigned long)ata_logical_sector_offset(parm)); 1168195534Sscottl 1169195534Sscottl if (parm->config == ATA_PROTO_CFA || 1170195534Sscottl (parm->support.command2 & ATA_SUPPORT_CFA)) 1171195534Sscottl printf("CFA supported\n"); 1172195534Sscottl 1173196658Smav printf("LBA%ssupported ", 1174195534Sscottl parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not "); 1175195534Sscottl if (lbasize) 1176195534Sscottl printf("%d sectors\n", lbasize); 1177195534Sscottl else 1178195534Sscottl printf("\n"); 1179195534Sscottl 1180196658Smav printf("LBA48%ssupported ", 1181195534Sscottl parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not "); 1182195534Sscottl if (lbasize48) 1183195534Sscottl printf("%ju sectors\n", (uintmax_t)lbasize48); 1184195534Sscottl else 1185195534Sscottl printf("\n"); 1186195534Sscottl 1187196658Smav printf("PIO supported PIO"); 1188197419Smav switch (ata_max_pmode(parm)) { 1189197419Smav case ATA_PIO4: 1190196658Smav printf("4"); 1191197419Smav break; 1192197419Smav case ATA_PIO3: 1193196658Smav printf("3"); 1194197419Smav break; 1195197419Smav case ATA_PIO2: 1196196658Smav printf("2"); 1197197419Smav break; 1198197419Smav case ATA_PIO1: 1199196658Smav printf("1"); 1200197419Smav break; 1201197419Smav default: 1202196658Smav printf("0"); 1203197419Smav } 1204197545Smav if ((parm->capabilities1 & ATA_SUPPORT_IORDY) == 0) 1205197545Smav printf(" w/o IORDY"); 1206196658Smav printf("\n"); 1207196658Smav 1208196658Smav printf("DMA%ssupported ", 1209195534Sscottl parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not "); 1210196658Smav if (parm->capabilities1 & ATA_SUPPORT_DMA) { 1211196658Smav if (parm->mwdmamodes & 0xff) { 1212196658Smav printf("WDMA"); 1213196658Smav if (parm->mwdmamodes & 0x04) 1214196658Smav printf("2"); 1215196658Smav else if (parm->mwdmamodes & 0x02) 1216196658Smav printf("1"); 1217196658Smav else if (parm->mwdmamodes & 0x01) 1218196658Smav printf("0"); 1219196658Smav printf(" "); 1220196658Smav } 1221196658Smav if ((parm->atavalid & ATA_FLAG_88) && 1222196658Smav (parm->udmamodes & 0xff)) { 1223196658Smav printf("UDMA"); 1224196658Smav if (parm->udmamodes & 0x40) 1225196658Smav printf("6"); 1226196658Smav else if (parm->udmamodes & 0x20) 1227196658Smav printf("5"); 1228196658Smav else if (parm->udmamodes & 0x10) 1229196658Smav printf("4"); 1230196658Smav else if (parm->udmamodes & 0x08) 1231196658Smav printf("3"); 1232196658Smav else if (parm->udmamodes & 0x04) 1233196658Smav printf("2"); 1234196658Smav else if (parm->udmamodes & 0x02) 1235196658Smav printf("1"); 1236196658Smav else if (parm->udmamodes & 0x01) 1237196658Smav printf("0"); 1238196658Smav printf(" "); 1239196658Smav } 1240196658Smav } 1241196658Smav printf("\n"); 1242195534Sscottl 1243197545Smav if (parm->media_rotation_rate == 1) { 1244197545Smav printf("media RPM non-rotating\n"); 1245197545Smav } else if (parm->media_rotation_rate >= 0x0401 && 1246197545Smav parm->media_rotation_rate <= 0xFFFE) { 1247197545Smav printf("media RPM %d\n", 1248197545Smav parm->media_rotation_rate); 1249197545Smav } 1250195534Sscottl 1251195534Sscottl printf("\nFeature " 1252214321Smav "Support Enabled Value Vendor\n"); 1253197545Smav printf("read ahead %s %s\n", 1254197545Smav parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no", 1255197545Smav parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no"); 1256195534Sscottl printf("write cache %s %s\n", 1257195534Sscottl parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no", 1258195534Sscottl parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no"); 1259197545Smav printf("flush cache %s %s\n", 1260197545Smav parm->support.command2 & ATA_SUPPORT_FLUSHCACHE ? "yes" : "no", 1261197545Smav parm->enabled.command2 & ATA_SUPPORT_FLUSHCACHE ? "yes" : "no"); 1262202694Smav printf("overlap %s\n", 1263202694Smav parm->capabilities1 & ATA_SUPPORT_OVERLAP ? "yes" : "no"); 1264202694Smav printf("Tagged Command Queuing (TCQ) %s %s", 1265202694Smav parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no", 1266202694Smav parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no"); 1267202694Smav if (parm->support.command2 & ATA_SUPPORT_QUEUED) { 1268202694Smav printf(" %d tags\n", 1269202694Smav ATA_QUEUE_LEN(parm->queue) + 1); 1270202694Smav } else 1271202694Smav printf("\n"); 1272214321Smav printf("Native Command Queuing (NCQ) "); 1273214321Smav if (parm->satacapabilities != 0xffff && 1274214321Smav (parm->satacapabilities & ATA_SUPPORT_NCQ)) { 1275214321Smav printf("yes %d tags\n", 1276214321Smav ATA_QUEUE_LEN(parm->queue) + 1); 1277214321Smav } else 1278214321Smav printf("no\n"); 1279195534Sscottl printf("SMART %s %s\n", 1280195534Sscottl parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no", 1281195534Sscottl parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no"); 1282195534Sscottl printf("microcode download %s %s\n", 1283195534Sscottl parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no", 1284195534Sscottl parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no"); 1285195534Sscottl printf("security %s %s\n", 1286195534Sscottl parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no", 1287195534Sscottl parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no"); 1288195534Sscottl printf("power management %s %s\n", 1289195534Sscottl parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no", 1290195534Sscottl parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no"); 1291214321Smav printf("advanced power management %s %s", 1292195534Sscottl parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no", 1293214321Smav parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no"); 1294214321Smav if (parm->support.command2 & ATA_SUPPORT_APM) { 1295214321Smav printf(" %d/0x%02X\n", 1296214321Smav parm->apm_value, parm->apm_value); 1297214321Smav } else 1298214321Smav printf("\n"); 1299214321Smav printf("automatic acoustic management %s %s", 1300195534Sscottl parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no", 1301214321Smav parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no"); 1302214321Smav if (parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC) { 1303214321Smav printf(" %d/0x%02X %d/0x%02X\n", 1304214321Smav ATA_ACOUSTIC_CURRENT(parm->acoustic), 1305214321Smav ATA_ACOUSTIC_CURRENT(parm->acoustic), 1306214321Smav ATA_ACOUSTIC_VENDOR(parm->acoustic), 1307214321Smav ATA_ACOUSTIC_VENDOR(parm->acoustic)); 1308214321Smav } else 1309214321Smav printf("\n"); 1310197545Smav printf("media status notification %s %s\n", 1311197545Smav parm->support.command2 & ATA_SUPPORT_NOTIFY ? "yes" : "no", 1312197545Smav parm->enabled.command2 & ATA_SUPPORT_NOTIFY ? "yes" : "no"); 1313197545Smav printf("power-up in Standby %s %s\n", 1314197545Smav parm->support.command2 & ATA_SUPPORT_STANDBY ? "yes" : "no", 1315197545Smav parm->enabled.command2 & ATA_SUPPORT_STANDBY ? "yes" : "no"); 1316214321Smav printf("write-read-verify %s %s", 1317197545Smav parm->support2 & ATA_SUPPORT_WRITEREADVERIFY ? "yes" : "no", 1318214321Smav parm->enabled2 & ATA_SUPPORT_WRITEREADVERIFY ? "yes" : "no"); 1319214321Smav if (parm->support2 & ATA_SUPPORT_WRITEREADVERIFY) { 1320214321Smav printf(" %d/0x%x\n", 1321214321Smav parm->wrv_mode, parm->wrv_mode); 1322214321Smav } else 1323214321Smav printf("\n"); 1324197545Smav printf("unload %s %s\n", 1325197545Smav parm->support.extension & ATA_SUPPORT_UNLOAD ? "yes" : "no", 1326197545Smav parm->enabled.extension & ATA_SUPPORT_UNLOAD ? "yes" : "no"); 1327197545Smav printf("free-fall %s %s\n", 1328197545Smav parm->support2 & ATA_SUPPORT_FREEFALL ? "yes" : "no", 1329197545Smav parm->enabled2 & ATA_SUPPORT_FREEFALL ? "yes" : "no"); 1330202694Smav printf("data set management (TRIM) %s\n", 1331202694Smav parm->support_dsm & ATA_SUPPORT_DSM_TRIM ? "yes" : "no"); 1332195534Sscottl} 1333195534Sscottl 1334195534Sscottlstatic int 1335195534Sscottlataidentify(struct cam_device *device, int retry_count, int timeout) 1336195534Sscottl{ 1337195534Sscottl union ccb *ccb; 1338195534Sscottl struct ata_params *ident_buf; 1339196658Smav struct ccb_getdev cgd; 1340195573Sscottl u_int i, error = 0; 1341195534Sscottl int16_t *ptr; 1342196658Smav 1343196658Smav if (get_cgd(device, &cgd) != 0) { 1344196658Smav warnx("couldn't get CGD"); 1345196658Smav return(1); 1346196658Smav } 1347195534Sscottl ccb = cam_getccb(device); 1348195534Sscottl 1349195534Sscottl if (ccb == NULL) { 1350195534Sscottl warnx("couldn't allocate CCB"); 1351195534Sscottl return(1); 1352195534Sscottl } 1353195534Sscottl 1354195534Sscottl /* cam_getccb cleans up the header, caller has to zero the payload */ 1355195534Sscottl bzero(&(&ccb->ccb_h)[1], 1356195534Sscottl sizeof(struct ccb_ataio) - sizeof(struct ccb_hdr)); 1357195534Sscottl 1358195573Sscottl ptr = (uint16_t *)malloc(sizeof(struct ata_params)); 1359195534Sscottl 1360195573Sscottl if (ptr == NULL) { 1361195534Sscottl cam_freeccb(ccb); 1362195534Sscottl warnx("can't malloc memory for identify\n"); 1363195534Sscottl return(1); 1364195534Sscottl } 1365195573Sscottl bzero(ptr, sizeof(struct ata_params)); 1366195534Sscottl 1367195534Sscottl cam_fill_ataio(&ccb->ataio, 1368195534Sscottl retry_count, 1369195534Sscottl NULL, 1370195534Sscottl /*flags*/CAM_DIR_IN, 1371195534Sscottl MSG_SIMPLE_Q_TAG, 1372195573Sscottl /*data_ptr*/(u_int8_t *)ptr, 1373195534Sscottl /*dxfer_len*/sizeof(struct ata_params), 1374195534Sscottl timeout ? timeout : 30 * 1000); 1375196658Smav if (cgd.protocol == PROTO_ATA) 1376196659Smav ata_28bit_cmd(&ccb->ataio, ATA_ATA_IDENTIFY, 0, 0, 0); 1377196658Smav else 1378196659Smav ata_28bit_cmd(&ccb->ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0); 1379195534Sscottl 1380195534Sscottl /* Disable freezing the device queue */ 1381195534Sscottl ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 1382195534Sscottl 1383195534Sscottl if (arglist & CAM_ARG_ERR_RECOVER) 1384195534Sscottl ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 1385195534Sscottl 1386195534Sscottl if (cam_send_ccb(device, ccb) < 0) { 1387195534Sscottl perror("error sending ATA identify"); 1388195534Sscottl 1389195534Sscottl if (arglist & CAM_ARG_VERBOSE) { 1390195534Sscottl cam_error_print(device, ccb, CAM_ESF_ALL, 1391195534Sscottl CAM_EPF_ALL, stderr); 1392195534Sscottl } 1393195534Sscottl 1394195573Sscottl free(ptr); 1395195534Sscottl cam_freeccb(ccb); 1396195534Sscottl return(1); 1397195534Sscottl } 1398195534Sscottl 1399195534Sscottl if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1400195534Sscottl error = 1; 1401195534Sscottl 1402195534Sscottl if (arglist & CAM_ARG_VERBOSE) { 1403195534Sscottl cam_error_print(device, ccb, CAM_ESF_ALL, 1404195534Sscottl CAM_EPF_ALL, stderr); 1405195534Sscottl } 1406195534Sscottl } 1407195534Sscottl 1408195534Sscottl cam_freeccb(ccb); 1409195534Sscottl 1410195534Sscottl if (error != 0) { 1411195573Sscottl free(ptr); 1412195534Sscottl return(error); 1413195534Sscottl } 1414195534Sscottl 1415195573Sscottl for (i = 0; i < sizeof(struct ata_params) / 2; i++) 1416195573Sscottl ptr[i] = le16toh(ptr[i]); 1417202694Smav if (arglist & CAM_ARG_VERBOSE) { 1418202694Smav fprintf(stdout, "%s%d: Raw identify data:\n", 1419202694Smav device->device_name, device->dev_unit_num); 1420202694Smav for (i = 0; i < sizeof(struct ata_params) / 2; i++) { 1421202694Smav if ((i % 8) == 0) 1422202694Smav fprintf(stdout, " %3d: ", i); 1423202694Smav fprintf(stdout, "%04x ", (uint16_t)ptr[i]); 1424202694Smav if ((i % 8) == 7) 1425202694Smav fprintf(stdout, "\n"); 1426202694Smav } 1427202694Smav } 1428195573Sscottl ident_buf = (struct ata_params *)ptr; 1429195534Sscottl if (strncmp(ident_buf->model, "FX", 2) && 1430195534Sscottl strncmp(ident_buf->model, "NEC", 3) && 1431195534Sscottl strncmp(ident_buf->model, "Pioneer", 7) && 1432195534Sscottl strncmp(ident_buf->model, "SHARP", 5)) { 1433195534Sscottl ata_bswap(ident_buf->model, sizeof(ident_buf->model)); 1434195534Sscottl ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); 1435195534Sscottl ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); 1436197545Smav ata_bswap(ident_buf->media_serial, sizeof(ident_buf->media_serial)); 1437195534Sscottl } 1438195534Sscottl ata_btrim(ident_buf->model, sizeof(ident_buf->model)); 1439195534Sscottl ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); 1440195534Sscottl ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); 1441195534Sscottl ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); 1442195534Sscottl ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); 1443195534Sscottl ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); 1444197545Smav ata_btrim(ident_buf->media_serial, sizeof(ident_buf->media_serial)); 1445197545Smav ata_bpack(ident_buf->media_serial, ident_buf->media_serial, 1446197545Smav sizeof(ident_buf->media_serial)); 1447195534Sscottl 1448195534Sscottl fprintf(stdout, "%s%d: ", device->device_name, 1449195534Sscottl device->dev_unit_num); 1450195534Sscottl ata_print_ident(ident_buf); 1451198709Smav camxferrate(device); 1452195534Sscottl atacapprint(ident_buf); 1453195534Sscottl 1454195534Sscottl free(ident_buf); 1455195534Sscottl 1456195534Sscottl return(0); 1457195534Sscottl} 145889471Sjoerg#endif /* MINIMALISTIC */ 145939214Sgibbs 146046938Sken/* 146146938Sken * Parse out a bus, or a bus, target and lun in the following 146246938Sken * format: 146346938Sken * bus 146446938Sken * bus:target 146546938Sken * bus:target:lun 146646938Sken * 146746938Sken * Returns the number of parsed components, or 0. 146846938Sken */ 146939214Sgibbsstatic int 1470118478Sjohanparse_btl(char *tstr, int *bus, int *target, int *lun, cam_argmask *arglst) 147146938Sken{ 147246938Sken char *tmpstr; 147346938Sken int convs = 0; 147446938Sken 147546938Sken while (isspace(*tstr) && (*tstr != '\0')) 147646938Sken tstr++; 147746938Sken 147846938Sken tmpstr = (char *)strtok(tstr, ":"); 147946938Sken if ((tmpstr != NULL) && (*tmpstr != '\0')) { 148046938Sken *bus = strtol(tmpstr, NULL, 0); 1481118478Sjohan *arglst |= CAM_ARG_BUS; 148246938Sken convs++; 148346938Sken tmpstr = (char *)strtok(NULL, ":"); 148446938Sken if ((tmpstr != NULL) && (*tmpstr != '\0')) { 148546938Sken *target = strtol(tmpstr, NULL, 0); 1486118478Sjohan *arglst |= CAM_ARG_TARGET; 148746938Sken convs++; 148846938Sken tmpstr = (char *)strtok(NULL, ":"); 148946938Sken if ((tmpstr != NULL) && (*tmpstr != '\0')) { 149046938Sken *lun = strtol(tmpstr, NULL, 0); 1491118478Sjohan *arglst |= CAM_ARG_LUN; 149246938Sken convs++; 149346938Sken } 149446938Sken } 149546938Sken } 149646938Sken 149746938Sken return convs; 149846938Sken} 149946938Sken 150046938Skenstatic int 150141962Smjacobdorescan_or_reset(int argc, char **argv, int rescan) 150239214Sgibbs{ 150369254Skris static const char must[] = 150489515Sken "you must specify \"all\", a bus, or a bus:target:lun to %s"; 150546938Sken int rv, error = 0; 150639214Sgibbs int bus = -1, target = -1, lun = -1; 150789515Sken char *tstr; 150839214Sgibbs 150939214Sgibbs if (argc < 3) { 151041962Smjacob warnx(must, rescan? "rescan" : "reset"); 151139214Sgibbs return(1); 151239214Sgibbs } 151389515Sken 151489515Sken tstr = argv[optind]; 151589515Sken while (isspace(*tstr) && (*tstr != '\0')) 151689515Sken tstr++; 151789515Sken if (strncasecmp(tstr, "all", strlen("all")) == 0) 151889515Sken arglist |= CAM_ARG_BUS; 151989515Sken else { 152089515Sken rv = parse_btl(argv[optind], &bus, &target, &lun, &arglist); 152189515Sken if (rv != 1 && rv != 3) { 152289515Sken warnx(must, rescan? "rescan" : "reset"); 152389515Sken return(1); 152489515Sken } 152539214Sgibbs } 152639214Sgibbs 152746938Sken if ((arglist & CAM_ARG_BUS) 152846938Sken && (arglist & CAM_ARG_TARGET) 152946938Sken && (arglist & CAM_ARG_LUN)) 153046938Sken error = scanlun_or_reset_dev(bus, target, lun, rescan); 153146938Sken else 153246938Sken error = rescan_or_reset_bus(bus, rescan); 153339214Sgibbs 153439214Sgibbs return(error); 153539214Sgibbs} 153639214Sgibbs 153739214Sgibbsstatic int 153841962Smjacobrescan_or_reset_bus(int bus, int rescan) 153939214Sgibbs{ 154089515Sken union ccb ccb, matchccb; 154189515Sken int fd, retval; 154289515Sken int bufsize; 154339214Sgibbs 154489515Sken retval = 0; 154539214Sgibbs 154639214Sgibbs if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { 1547166324Swilko warnx("error opening transport layer device %s", XPT_DEVICE); 154839214Sgibbs warn("%s", XPT_DEVICE); 154939214Sgibbs return(1); 155039214Sgibbs } 155139214Sgibbs 155289515Sken if (bus != -1) { 155389515Sken ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS : XPT_RESET_BUS; 155489515Sken ccb.ccb_h.path_id = bus; 155589515Sken ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; 155689515Sken ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; 155789515Sken ccb.crcn.flags = CAM_FLAG_NONE; 155839214Sgibbs 155989515Sken /* run this at a low priority */ 156089515Sken ccb.ccb_h.pinfo.priority = 5; 156139214Sgibbs 156289515Sken if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 156389515Sken warn("CAMIOCOMMAND ioctl failed"); 156489515Sken close(fd); 156589515Sken return(1); 156689515Sken } 156789515Sken 156889515Sken if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 156989515Sken fprintf(stdout, "%s of bus %d was successful\n", 157089515Sken rescan ? "Re-scan" : "Reset", bus); 157189515Sken } else { 157289515Sken fprintf(stdout, "%s of bus %d returned error %#x\n", 157389515Sken rescan ? "Re-scan" : "Reset", bus, 157489515Sken ccb.ccb_h.status & CAM_STATUS_MASK); 157589515Sken retval = 1; 157689515Sken } 157789515Sken 157839214Sgibbs close(fd); 157989515Sken return(retval); 158089515Sken 158139214Sgibbs } 158239214Sgibbs 158339214Sgibbs 158489515Sken /* 158589515Sken * The right way to handle this is to modify the xpt so that it can 158689515Sken * handle a wildcarded bus in a rescan or reset CCB. At the moment 158789515Sken * that isn't implemented, so instead we enumerate the busses and 158889515Sken * send the rescan or reset to those busses in the case where the 158989515Sken * given bus is -1 (wildcard). We don't send a rescan or reset 159089515Sken * to the xpt bus; sending a rescan to the xpt bus is effectively a 159189515Sken * no-op, sending a rescan to the xpt bus would result in a status of 159289515Sken * CAM_REQ_INVALID. 159389515Sken */ 159489515Sken bzero(&(&matchccb.ccb_h)[1], 159589515Sken sizeof(struct ccb_dev_match) - sizeof(struct ccb_hdr)); 159689515Sken matchccb.ccb_h.func_code = XPT_DEV_MATCH; 1597215507Srstone matchccb.ccb_h.path_id = CAM_BUS_WILDCARD; 159889515Sken bufsize = sizeof(struct dev_match_result) * 20; 159989515Sken matchccb.cdm.match_buf_len = bufsize; 160089515Sken matchccb.cdm.matches=(struct dev_match_result *)malloc(bufsize); 160189515Sken if (matchccb.cdm.matches == NULL) { 160289515Sken warnx("can't malloc memory for matches"); 160389515Sken retval = 1; 160489515Sken goto bailout; 160539214Sgibbs } 160689515Sken matchccb.cdm.num_matches = 0; 160789515Sken 160889515Sken matchccb.cdm.num_patterns = 1; 160989515Sken matchccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern); 161089515Sken 161189515Sken matchccb.cdm.patterns = (struct dev_match_pattern *)malloc( 161289515Sken matchccb.cdm.pattern_buf_len); 161389515Sken if (matchccb.cdm.patterns == NULL) { 161489515Sken warnx("can't malloc memory for patterns"); 161589515Sken retval = 1; 161689515Sken goto bailout; 161789515Sken } 161889515Sken matchccb.cdm.patterns[0].type = DEV_MATCH_BUS; 161989515Sken matchccb.cdm.patterns[0].pattern.bus_pattern.flags = BUS_MATCH_ANY; 162089515Sken 162189515Sken do { 1622102192Sjohan unsigned int i; 162389515Sken 162489515Sken if (ioctl(fd, CAMIOCOMMAND, &matchccb) == -1) { 162589515Sken warn("CAMIOCOMMAND ioctl failed"); 162689515Sken retval = 1; 162789515Sken goto bailout; 162889515Sken } 162989515Sken 163089515Sken if ((matchccb.ccb_h.status != CAM_REQ_CMP) 163189515Sken || ((matchccb.cdm.status != CAM_DEV_MATCH_LAST) 163289515Sken && (matchccb.cdm.status != CAM_DEV_MATCH_MORE))) { 163389515Sken warnx("got CAM error %#x, CDM error %d\n", 163489515Sken matchccb.ccb_h.status, matchccb.cdm.status); 163589515Sken retval = 1; 163689515Sken goto bailout; 163789515Sken } 163889515Sken 163989515Sken for (i = 0; i < matchccb.cdm.num_matches; i++) { 164089515Sken struct bus_match_result *bus_result; 164189515Sken 164289515Sken /* This shouldn't happen. */ 164389515Sken if (matchccb.cdm.matches[i].type != DEV_MATCH_BUS) 164489515Sken continue; 164589515Sken 164689515Sken bus_result = &matchccb.cdm.matches[i].result.bus_result; 164789515Sken 164889515Sken /* 164989515Sken * We don't want to rescan or reset the xpt bus. 165089515Sken * See above. 165189515Sken */ 1652102192Sjohan if ((int)bus_result->path_id == -1) 165389515Sken continue; 165489515Sken 165589515Sken ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS : 165689515Sken XPT_RESET_BUS; 165789515Sken ccb.ccb_h.path_id = bus_result->path_id; 165889515Sken ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; 165989515Sken ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; 166089515Sken ccb.crcn.flags = CAM_FLAG_NONE; 166189515Sken 166289515Sken /* run this at a low priority */ 166389515Sken ccb.ccb_h.pinfo.priority = 5; 166489515Sken 166589515Sken if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 166689515Sken warn("CAMIOCOMMAND ioctl failed"); 166789515Sken retval = 1; 166889515Sken goto bailout; 166989515Sken } 167089515Sken 167189515Sken if ((ccb.ccb_h.status & CAM_STATUS_MASK) ==CAM_REQ_CMP){ 167289515Sken fprintf(stdout, "%s of bus %d was successful\n", 167389515Sken rescan? "Re-scan" : "Reset", 167489515Sken bus_result->path_id); 167589515Sken } else { 167689515Sken /* 167789515Sken * Don't bail out just yet, maybe the other 167889515Sken * rescan or reset commands will complete 167989515Sken * successfully. 168089515Sken */ 168189515Sken fprintf(stderr, "%s of bus %d returned error " 168289515Sken "%#x\n", rescan? "Re-scan" : "Reset", 168389515Sken bus_result->path_id, 168489515Sken ccb.ccb_h.status & CAM_STATUS_MASK); 168589515Sken retval = 1; 168689515Sken } 168789515Sken } 168889515Sken } while ((matchccb.ccb_h.status == CAM_REQ_CMP) 168989515Sken && (matchccb.cdm.status == CAM_DEV_MATCH_MORE)); 169089515Sken 169189515Skenbailout: 169289515Sken 169389515Sken if (fd != -1) 169489515Sken close(fd); 169589515Sken 169689515Sken if (matchccb.cdm.patterns != NULL) 169789515Sken free(matchccb.cdm.patterns); 169889515Sken if (matchccb.cdm.matches != NULL) 169989515Sken free(matchccb.cdm.matches); 170089515Sken 170189515Sken return(retval); 170239214Sgibbs} 170339214Sgibbs 170439214Sgibbsstatic int 170541962Smjacobscanlun_or_reset_dev(int bus, int target, int lun, int scan) 170639214Sgibbs{ 170739214Sgibbs union ccb ccb; 170852703Sken struct cam_device *device; 170939214Sgibbs int fd; 171039214Sgibbs 171161233Sken device = NULL; 171261233Sken 171339214Sgibbs if (bus < 0) { 171439214Sgibbs warnx("invalid bus number %d", bus); 171539214Sgibbs return(1); 171639214Sgibbs } 171739214Sgibbs 171839214Sgibbs if (target < 0) { 171939214Sgibbs warnx("invalid target number %d", target); 172039214Sgibbs return(1); 172139214Sgibbs } 172239214Sgibbs 172339214Sgibbs if (lun < 0) { 172439214Sgibbs warnx("invalid lun number %d", lun); 172539214Sgibbs return(1); 172639214Sgibbs } 172739214Sgibbs 172852703Sken fd = -1; 172952703Sken 173052703Sken bzero(&ccb, sizeof(union ccb)); 173152703Sken 173252703Sken if (scan) { 173352703Sken if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { 1734166324Swilko warnx("error opening transport layer device %s\n", 173552703Sken XPT_DEVICE); 173652703Sken warn("%s", XPT_DEVICE); 173752703Sken return(1); 173852703Sken } 173952703Sken } else { 174052703Sken device = cam_open_btl(bus, target, lun, O_RDWR, NULL); 174152703Sken if (device == NULL) { 174252703Sken warnx("%s", cam_errbuf); 174352703Sken return(1); 174452703Sken } 174539214Sgibbs } 174639214Sgibbs 174741962Smjacob ccb.ccb_h.func_code = (scan)? XPT_SCAN_LUN : XPT_RESET_DEV; 174839214Sgibbs ccb.ccb_h.path_id = bus; 174939214Sgibbs ccb.ccb_h.target_id = target; 175039214Sgibbs ccb.ccb_h.target_lun = lun; 175152703Sken ccb.ccb_h.timeout = 5000; 175239214Sgibbs ccb.crcn.flags = CAM_FLAG_NONE; 175339214Sgibbs 175439214Sgibbs /* run this at a low priority */ 175539214Sgibbs ccb.ccb_h.pinfo.priority = 5; 175639214Sgibbs 175752703Sken if (scan) { 175852703Sken if (ioctl(fd, CAMIOCOMMAND, &ccb) < 0) { 175952703Sken warn("CAMIOCOMMAND ioctl failed"); 176052703Sken close(fd); 176152703Sken return(1); 176252703Sken } 176352703Sken } else { 176452703Sken if (cam_send_ccb(device, &ccb) < 0) { 176552703Sken warn("error sending XPT_RESET_DEV CCB"); 176652703Sken cam_close_device(device); 176752703Sken return(1); 176852703Sken } 176939214Sgibbs } 177039214Sgibbs 177152703Sken if (scan) 177252703Sken close(fd); 177352703Sken else 177452703Sken cam_close_device(device); 177539214Sgibbs 177652703Sken /* 177752703Sken * An error code of CAM_BDR_SENT is normal for a BDR request. 177852703Sken */ 177952703Sken if (((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 178052703Sken || ((!scan) 178152703Sken && ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_BDR_SENT))) { 178241962Smjacob fprintf(stdout, "%s of %d:%d:%d was successful\n", 178341962Smjacob scan? "Re-scan" : "Reset", bus, target, lun); 178439214Sgibbs return(0); 178539214Sgibbs } else { 178641962Smjacob fprintf(stdout, "%s of %d:%d:%d returned error %#x\n", 178741962Smjacob scan? "Re-scan" : "Reset", bus, target, lun, 178841962Smjacob ccb.ccb_h.status & CAM_STATUS_MASK); 178939214Sgibbs return(1); 179039214Sgibbs } 179139214Sgibbs} 179239214Sgibbs 179389471Sjoerg#ifndef MINIMALISTIC 179439214Sgibbsstatic int 179539214Sgibbsreaddefects(struct cam_device *device, int argc, char **argv, 179639214Sgibbs char *combinedopt, int retry_count, int timeout) 179739214Sgibbs{ 179839214Sgibbs union ccb *ccb = NULL; 179939214Sgibbs struct scsi_read_defect_data_10 *rdd_cdb; 180039214Sgibbs u_int8_t *defect_list = NULL; 180139214Sgibbs u_int32_t dlist_length = 65000; 180239214Sgibbs u_int32_t returned_length = 0; 180339214Sgibbs u_int32_t num_returned = 0; 180439214Sgibbs u_int8_t returned_format; 1805102192Sjohan unsigned int i; 180639214Sgibbs int c, error = 0; 180739214Sgibbs int lists_specified = 0; 180839214Sgibbs 180939214Sgibbs while ((c = getopt(argc, argv, combinedopt)) != -1) { 181039214Sgibbs switch(c){ 181139214Sgibbs case 'f': 181239214Sgibbs { 181339214Sgibbs char *tstr; 181439214Sgibbs tstr = optarg; 181539214Sgibbs while (isspace(*tstr) && (*tstr != '\0')) 181639214Sgibbs tstr++; 181739214Sgibbs if (strcmp(tstr, "block") == 0) 181839214Sgibbs arglist |= CAM_ARG_FORMAT_BLOCK; 181939214Sgibbs else if (strcmp(tstr, "bfi") == 0) 182039214Sgibbs arglist |= CAM_ARG_FORMAT_BFI; 182139214Sgibbs else if (strcmp(tstr, "phys") == 0) 182239214Sgibbs arglist |= CAM_ARG_FORMAT_PHYS; 182339214Sgibbs else { 182439214Sgibbs error = 1; 182539214Sgibbs warnx("invalid defect format %s", tstr); 182639214Sgibbs goto defect_bailout; 182739214Sgibbs } 182839214Sgibbs break; 182939214Sgibbs } 183039214Sgibbs case 'G': 183139214Sgibbs arglist |= CAM_ARG_GLIST; 183239214Sgibbs break; 183339214Sgibbs case 'P': 183439214Sgibbs arglist |= CAM_ARG_PLIST; 183539214Sgibbs break; 183639214Sgibbs default: 183739214Sgibbs break; 183839214Sgibbs } 183939214Sgibbs } 184039214Sgibbs 184139214Sgibbs ccb = cam_getccb(device); 184239214Sgibbs 184339214Sgibbs /* 184439214Sgibbs * Hopefully 65000 bytes is enough to hold the defect list. If it 184539214Sgibbs * isn't, the disk is probably dead already. We'd have to go with 184639214Sgibbs * 12 byte command (i.e. alloc_length is 32 bits instead of 16) 184739214Sgibbs * to hold them all. 184839214Sgibbs */ 184939214Sgibbs defect_list = malloc(dlist_length); 185069471Sjedgar if (defect_list == NULL) { 185169471Sjedgar warnx("can't malloc memory for defect list"); 185269471Sjedgar error = 1; 185369471Sjedgar goto defect_bailout; 185469471Sjedgar } 185539214Sgibbs 185639214Sgibbs rdd_cdb =(struct scsi_read_defect_data_10 *)&ccb->csio.cdb_io.cdb_bytes; 185739214Sgibbs 185839214Sgibbs /* 185939214Sgibbs * cam_getccb() zeros the CCB header only. So we need to zero the 186039214Sgibbs * payload portion of the ccb. 186139214Sgibbs */ 186246581Sken bzero(&(&ccb->ccb_h)[1], 186346581Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 186439214Sgibbs 186539214Sgibbs cam_fill_csio(&ccb->csio, 186639214Sgibbs /*retries*/ retry_count, 186739214Sgibbs /*cbfcnp*/ NULL, 186851723Sken /*flags*/ CAM_DIR_IN | ((arglist & CAM_ARG_ERR_RECOVER) ? 186951723Sken CAM_PASS_ERR_RECOVER : 0), 187039214Sgibbs /*tag_action*/ MSG_SIMPLE_Q_TAG, 187139214Sgibbs /*data_ptr*/ defect_list, 187239214Sgibbs /*dxfer_len*/ dlist_length, 187339214Sgibbs /*sense_len*/ SSD_FULL_SIZE, 187439214Sgibbs /*cdb_len*/ sizeof(struct scsi_read_defect_data_10), 187539214Sgibbs /*timeout*/ timeout ? timeout : 5000); 187639214Sgibbs 187739214Sgibbs rdd_cdb->opcode = READ_DEFECT_DATA_10; 187839214Sgibbs if (arglist & CAM_ARG_FORMAT_BLOCK) 187939214Sgibbs rdd_cdb->format = SRDD10_BLOCK_FORMAT; 188039214Sgibbs else if (arglist & CAM_ARG_FORMAT_BFI) 188139214Sgibbs rdd_cdb->format = SRDD10_BYTES_FROM_INDEX_FORMAT; 188239214Sgibbs else if (arglist & CAM_ARG_FORMAT_PHYS) 188339214Sgibbs rdd_cdb->format = SRDD10_PHYSICAL_SECTOR_FORMAT; 188439214Sgibbs else { 188539214Sgibbs error = 1; 188639214Sgibbs warnx("no defect list format specified"); 188739214Sgibbs goto defect_bailout; 188839214Sgibbs } 188939214Sgibbs if (arglist & CAM_ARG_PLIST) { 189039214Sgibbs rdd_cdb->format |= SRDD10_PLIST; 189139214Sgibbs lists_specified++; 189239214Sgibbs } 189339214Sgibbs 189439214Sgibbs if (arglist & CAM_ARG_GLIST) { 189539214Sgibbs rdd_cdb->format |= SRDD10_GLIST; 189639214Sgibbs lists_specified++; 189739214Sgibbs } 189839214Sgibbs 189939214Sgibbs scsi_ulto2b(dlist_length, rdd_cdb->alloc_length); 190039214Sgibbs 190139214Sgibbs /* Disable freezing the device queue */ 190239214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 190339214Sgibbs 190439214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 190539214Sgibbs perror("error reading defect list"); 190639214Sgibbs 190739214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 190874840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 190974840Sken CAM_EPF_ALL, stderr); 191039214Sgibbs } 191139214Sgibbs 191239214Sgibbs error = 1; 191339214Sgibbs goto defect_bailout; 191439214Sgibbs } 191539214Sgibbs 191639214Sgibbs returned_length = scsi_2btoul(((struct 191739214Sgibbs scsi_read_defect_data_hdr_10 *)defect_list)->length); 191839214Sgibbs 191939214Sgibbs returned_format = ((struct scsi_read_defect_data_hdr_10 *) 192039214Sgibbs defect_list)->format; 192139214Sgibbs 192274840Sken if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) 192374840Sken && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) 192474840Sken && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) { 192539214Sgibbs struct scsi_sense_data *sense; 192639214Sgibbs int error_code, sense_key, asc, ascq; 192739214Sgibbs 192839214Sgibbs sense = &ccb->csio.sense_data; 1929225950Sken scsi_extract_sense_len(sense, ccb->csio.sense_len - 1930225950Sken ccb->csio.sense_resid, &error_code, &sense_key, &asc, 1931225950Sken &ascq, /*show_errors*/ 1); 193239214Sgibbs 193339214Sgibbs /* 193439214Sgibbs * According to the SCSI spec, if the disk doesn't support 193539214Sgibbs * the requested format, it will generally return a sense 193639214Sgibbs * key of RECOVERED ERROR, and an additional sense code 193739214Sgibbs * of "DEFECT LIST NOT FOUND". So, we check for that, and 193839214Sgibbs * also check to make sure that the returned length is 193939214Sgibbs * greater than 0, and then print out whatever format the 194039214Sgibbs * disk gave us. 194139214Sgibbs */ 194239214Sgibbs if ((sense_key == SSD_KEY_RECOVERED_ERROR) 194339214Sgibbs && (asc == 0x1c) && (ascq == 0x00) 194439214Sgibbs && (returned_length > 0)) { 194539214Sgibbs warnx("requested defect format not available"); 194639214Sgibbs switch(returned_format & SRDDH10_DLIST_FORMAT_MASK) { 194739214Sgibbs case SRDD10_BLOCK_FORMAT: 194839214Sgibbs warnx("Device returned block format"); 194939214Sgibbs break; 195039214Sgibbs case SRDD10_BYTES_FROM_INDEX_FORMAT: 195139214Sgibbs warnx("Device returned bytes from index" 195239214Sgibbs " format"); 195339214Sgibbs break; 195439214Sgibbs case SRDD10_PHYSICAL_SECTOR_FORMAT: 195539214Sgibbs warnx("Device returned physical sector format"); 195639214Sgibbs break; 195739214Sgibbs default: 195839214Sgibbs error = 1; 195939214Sgibbs warnx("Device returned unknown defect" 196039214Sgibbs " data format %#x", returned_format); 196139214Sgibbs goto defect_bailout; 196239214Sgibbs break; /* NOTREACHED */ 196339214Sgibbs } 196439214Sgibbs } else { 196539214Sgibbs error = 1; 196639214Sgibbs warnx("Error returned from read defect data command"); 196774840Sken if (arglist & CAM_ARG_VERBOSE) 196874840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 196974840Sken CAM_EPF_ALL, stderr); 197039214Sgibbs goto defect_bailout; 197139214Sgibbs } 197287378Sken } else if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 197374840Sken error = 1; 197474840Sken warnx("Error returned from read defect data command"); 197574840Sken if (arglist & CAM_ARG_VERBOSE) 197674840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 197774840Sken CAM_EPF_ALL, stderr); 197874840Sken goto defect_bailout; 197939214Sgibbs } 198039214Sgibbs 198139214Sgibbs /* 198239214Sgibbs * XXX KDM I should probably clean up the printout format for the 1983214321Smav * disk defects. 198439214Sgibbs */ 198539214Sgibbs switch (returned_format & SRDDH10_DLIST_FORMAT_MASK){ 198639214Sgibbs case SRDDH10_PHYSICAL_SECTOR_FORMAT: 198739214Sgibbs { 198839214Sgibbs struct scsi_defect_desc_phys_sector *dlist; 198939214Sgibbs 199039214Sgibbs dlist = (struct scsi_defect_desc_phys_sector *) 199139214Sgibbs (defect_list + 199239214Sgibbs sizeof(struct scsi_read_defect_data_hdr_10)); 199339214Sgibbs 199439214Sgibbs num_returned = returned_length / 199539214Sgibbs sizeof(struct scsi_defect_desc_phys_sector); 199639214Sgibbs 199739214Sgibbs fprintf(stderr, "Got %d defect", num_returned); 199839214Sgibbs 199939214Sgibbs if ((lists_specified == 0) || (num_returned == 0)) { 200039214Sgibbs fprintf(stderr, "s.\n"); 200139214Sgibbs break; 200239214Sgibbs } else if (num_returned == 1) 200339214Sgibbs fprintf(stderr, ":\n"); 200439214Sgibbs else 200539214Sgibbs fprintf(stderr, "s:\n"); 200639214Sgibbs 200739214Sgibbs for (i = 0; i < num_returned; i++) { 200839214Sgibbs fprintf(stdout, "%d:%d:%d\n", 200939214Sgibbs scsi_3btoul(dlist[i].cylinder), 201039214Sgibbs dlist[i].head, 201139214Sgibbs scsi_4btoul(dlist[i].sector)); 201239214Sgibbs } 201339214Sgibbs break; 201439214Sgibbs } 201539214Sgibbs case SRDDH10_BYTES_FROM_INDEX_FORMAT: 201639214Sgibbs { 201739214Sgibbs struct scsi_defect_desc_bytes_from_index *dlist; 201839214Sgibbs 201939214Sgibbs dlist = (struct scsi_defect_desc_bytes_from_index *) 202039214Sgibbs (defect_list + 202139214Sgibbs sizeof(struct scsi_read_defect_data_hdr_10)); 202239214Sgibbs 202339214Sgibbs num_returned = returned_length / 202439214Sgibbs sizeof(struct scsi_defect_desc_bytes_from_index); 202539214Sgibbs 202639214Sgibbs fprintf(stderr, "Got %d defect", num_returned); 202739214Sgibbs 202839214Sgibbs if ((lists_specified == 0) || (num_returned == 0)) { 202939214Sgibbs fprintf(stderr, "s.\n"); 203039214Sgibbs break; 203139214Sgibbs } else if (num_returned == 1) 203239214Sgibbs fprintf(stderr, ":\n"); 203339214Sgibbs else 203439214Sgibbs fprintf(stderr, "s:\n"); 203539214Sgibbs 203639214Sgibbs for (i = 0; i < num_returned; i++) { 203739214Sgibbs fprintf(stdout, "%d:%d:%d\n", 203839214Sgibbs scsi_3btoul(dlist[i].cylinder), 203939214Sgibbs dlist[i].head, 204039214Sgibbs scsi_4btoul(dlist[i].bytes_from_index)); 204139214Sgibbs } 204239214Sgibbs break; 204339214Sgibbs } 204439214Sgibbs case SRDDH10_BLOCK_FORMAT: 204539214Sgibbs { 204639214Sgibbs struct scsi_defect_desc_block *dlist; 204739214Sgibbs 204839214Sgibbs dlist = (struct scsi_defect_desc_block *)(defect_list + 204939214Sgibbs sizeof(struct scsi_read_defect_data_hdr_10)); 205039214Sgibbs 205139214Sgibbs num_returned = returned_length / 205239214Sgibbs sizeof(struct scsi_defect_desc_block); 205339214Sgibbs 205439214Sgibbs fprintf(stderr, "Got %d defect", num_returned); 205539214Sgibbs 205639214Sgibbs if ((lists_specified == 0) || (num_returned == 0)) { 205739214Sgibbs fprintf(stderr, "s.\n"); 205839214Sgibbs break; 205939214Sgibbs } else if (num_returned == 1) 206039214Sgibbs fprintf(stderr, ":\n"); 206139214Sgibbs else 206239214Sgibbs fprintf(stderr, "s:\n"); 206339214Sgibbs 206439214Sgibbs for (i = 0; i < num_returned; i++) 206539214Sgibbs fprintf(stdout, "%u\n", 206639214Sgibbs scsi_4btoul(dlist[i].address)); 206739214Sgibbs break; 206839214Sgibbs } 206939214Sgibbs default: 207039214Sgibbs fprintf(stderr, "Unknown defect format %d\n", 207139214Sgibbs returned_format & SRDDH10_DLIST_FORMAT_MASK); 207239214Sgibbs error = 1; 207339214Sgibbs break; 207439214Sgibbs } 207539214Sgibbsdefect_bailout: 207639214Sgibbs 207739214Sgibbs if (defect_list != NULL) 207839214Sgibbs free(defect_list); 207939214Sgibbs 208039214Sgibbs if (ccb != NULL) 208139214Sgibbs cam_freeccb(ccb); 208239214Sgibbs 208339214Sgibbs return(error); 208439214Sgibbs} 208589471Sjoerg#endif /* MINIMALISTIC */ 208639214Sgibbs 208739214Sgibbs#if 0 208839214Sgibbsvoid 208939214Sgibbsreassignblocks(struct cam_device *device, u_int32_t *blocks, int num_blocks) 209039214Sgibbs{ 209139214Sgibbs union ccb *ccb; 2092214321Smav 209339214Sgibbs ccb = cam_getccb(device); 209439214Sgibbs 209539214Sgibbs cam_freeccb(ccb); 209639214Sgibbs} 209739214Sgibbs#endif 209839214Sgibbs 209989471Sjoerg#ifndef MINIMALISTIC 210039214Sgibbsvoid 210139214Sgibbsmode_sense(struct cam_device *device, int mode_page, int page_control, 210239214Sgibbs int dbd, int retry_count, int timeout, u_int8_t *data, int datalen) 210339214Sgibbs{ 210439214Sgibbs union ccb *ccb; 210539214Sgibbs int retval; 210639214Sgibbs 210739214Sgibbs ccb = cam_getccb(device); 210839214Sgibbs 210939214Sgibbs if (ccb == NULL) 211039214Sgibbs errx(1, "mode_sense: couldn't allocate CCB"); 211139214Sgibbs 211246581Sken bzero(&(&ccb->ccb_h)[1], 211346581Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 211439214Sgibbs 211539214Sgibbs scsi_mode_sense(&ccb->csio, 211639214Sgibbs /* retries */ retry_count, 211739214Sgibbs /* cbfcnp */ NULL, 211839214Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 211939214Sgibbs /* dbd */ dbd, 212039214Sgibbs /* page_code */ page_control << 6, 212139214Sgibbs /* page */ mode_page, 212239214Sgibbs /* param_buf */ data, 212339214Sgibbs /* param_len */ datalen, 212439214Sgibbs /* sense_len */ SSD_FULL_SIZE, 212539214Sgibbs /* timeout */ timeout ? timeout : 5000); 212639214Sgibbs 212739214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 212839214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 212939214Sgibbs 213039214Sgibbs /* Disable freezing the device queue */ 213139214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 213239214Sgibbs 213339214Sgibbs if (((retval = cam_send_ccb(device, ccb)) < 0) 213439214Sgibbs || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 213539214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 213674840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 213774840Sken CAM_EPF_ALL, stderr); 213839214Sgibbs } 213939214Sgibbs cam_freeccb(ccb); 214039214Sgibbs cam_close_device(device); 214139214Sgibbs if (retval < 0) 214239214Sgibbs err(1, "error sending mode sense command"); 214339214Sgibbs else 214439214Sgibbs errx(1, "error sending mode sense command"); 214539214Sgibbs } 214639214Sgibbs 214739214Sgibbs cam_freeccb(ccb); 214839214Sgibbs} 214939214Sgibbs 215039214Sgibbsvoid 215139214Sgibbsmode_select(struct cam_device *device, int save_pages, int retry_count, 215239214Sgibbs int timeout, u_int8_t *data, int datalen) 215339214Sgibbs{ 215439214Sgibbs union ccb *ccb; 215539214Sgibbs int retval; 215639214Sgibbs 215739214Sgibbs ccb = cam_getccb(device); 215839214Sgibbs 215939214Sgibbs if (ccb == NULL) 216039214Sgibbs errx(1, "mode_select: couldn't allocate CCB"); 216139214Sgibbs 216246581Sken bzero(&(&ccb->ccb_h)[1], 216346581Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 216439214Sgibbs 216539214Sgibbs scsi_mode_select(&ccb->csio, 216639214Sgibbs /* retries */ retry_count, 216739214Sgibbs /* cbfcnp */ NULL, 216839214Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 216939214Sgibbs /* scsi_page_fmt */ 1, 217039214Sgibbs /* save_pages */ save_pages, 217139214Sgibbs /* param_buf */ data, 217239214Sgibbs /* param_len */ datalen, 217339214Sgibbs /* sense_len */ SSD_FULL_SIZE, 217439214Sgibbs /* timeout */ timeout ? timeout : 5000); 217539214Sgibbs 217639214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 217739214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 217839214Sgibbs 217939214Sgibbs /* Disable freezing the device queue */ 218039214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 218139214Sgibbs 218239214Sgibbs if (((retval = cam_send_ccb(device, ccb)) < 0) 218339214Sgibbs || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 218439214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 218574840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 218674840Sken CAM_EPF_ALL, stderr); 218739214Sgibbs } 218839214Sgibbs cam_freeccb(ccb); 218939214Sgibbs cam_close_device(device); 219039214Sgibbs 219139214Sgibbs if (retval < 0) 219239214Sgibbs err(1, "error sending mode select command"); 219339214Sgibbs else 219439214Sgibbs errx(1, "error sending mode select command"); 2195214321Smav 219639214Sgibbs } 219739214Sgibbs 219839214Sgibbs cam_freeccb(ccb); 219939214Sgibbs} 220039214Sgibbs 220139214Sgibbsvoid 220239214Sgibbsmodepage(struct cam_device *device, int argc, char **argv, char *combinedopt, 220339214Sgibbs int retry_count, int timeout) 220439214Sgibbs{ 220539214Sgibbs int c, mode_page = -1, page_control = 0; 220664382Skbyanc int binary = 0, list = 0; 220739214Sgibbs 220839214Sgibbs while ((c = getopt(argc, argv, combinedopt)) != -1) { 220939214Sgibbs switch(c) { 221064382Skbyanc case 'b': 221164382Skbyanc binary = 1; 221264382Skbyanc break; 221339214Sgibbs case 'd': 221439214Sgibbs arglist |= CAM_ARG_DBD; 221539214Sgibbs break; 221639214Sgibbs case 'e': 221739214Sgibbs arglist |= CAM_ARG_MODE_EDIT; 221839214Sgibbs break; 221964382Skbyanc case 'l': 222064382Skbyanc list = 1; 222164382Skbyanc break; 222239214Sgibbs case 'm': 222339214Sgibbs mode_page = strtol(optarg, NULL, 0); 222439214Sgibbs if (mode_page < 0) 222539214Sgibbs errx(1, "invalid mode page %d", mode_page); 222639214Sgibbs break; 222739214Sgibbs case 'P': 222839214Sgibbs page_control = strtol(optarg, NULL, 0); 222939214Sgibbs if ((page_control < 0) || (page_control > 3)) 223039214Sgibbs errx(1, "invalid page control field %d", 223139214Sgibbs page_control); 223239214Sgibbs arglist |= CAM_ARG_PAGE_CNTL; 223339214Sgibbs break; 223439214Sgibbs default: 223539214Sgibbs break; 223639214Sgibbs } 223739214Sgibbs } 223839214Sgibbs 223964382Skbyanc if (mode_page == -1 && list == 0) 224039214Sgibbs errx(1, "you must specify a mode page!"); 224139214Sgibbs 224264382Skbyanc if (list) { 224364382Skbyanc mode_list(device, page_control, arglist & CAM_ARG_DBD, 224464382Skbyanc retry_count, timeout); 224564382Skbyanc } else { 224664382Skbyanc mode_edit(device, mode_page, page_control, 224764382Skbyanc arglist & CAM_ARG_DBD, arglist & CAM_ARG_MODE_EDIT, binary, 224864382Skbyanc retry_count, timeout); 224964382Skbyanc } 225039214Sgibbs} 225139214Sgibbs 225239214Sgibbsstatic int 225339214Sgibbsscsicmd(struct cam_device *device, int argc, char **argv, char *combinedopt, 225439214Sgibbs int retry_count, int timeout) 225539214Sgibbs{ 225639214Sgibbs union ccb *ccb; 225739214Sgibbs u_int32_t flags = CAM_DIR_NONE; 225839214Sgibbs u_int8_t *data_ptr = NULL; 225939214Sgibbs u_int8_t cdb[20]; 2260196831Smav u_int8_t atacmd[12]; 226139214Sgibbs struct get_hook hook; 226239214Sgibbs int c, data_bytes = 0; 226339214Sgibbs int cdb_len = 0; 2264196831Smav int atacmd_len = 0; 2265207498Smav int dmacmd = 0; 2266207498Smav int fpdmacmd = 0; 2267196831Smav int need_res = 0; 2268196831Smav char *datastr = NULL, *tstr, *resstr = NULL; 226939214Sgibbs int error = 0; 2270196831Smav int fd_data = 0, fd_res = 0; 227139214Sgibbs int retval; 227239214Sgibbs 227339214Sgibbs ccb = cam_getccb(device); 227439214Sgibbs 227539214Sgibbs if (ccb == NULL) { 227639214Sgibbs warnx("scsicmd: error allocating ccb"); 227739214Sgibbs return(1); 227839214Sgibbs } 227939214Sgibbs 228046581Sken bzero(&(&ccb->ccb_h)[1], 2281196831Smav sizeof(union ccb) - sizeof(struct ccb_hdr)); 228239214Sgibbs 228339214Sgibbs while ((c = getopt(argc, argv, combinedopt)) != -1) { 228439214Sgibbs switch(c) { 2285196831Smav case 'a': 2286196831Smav tstr = optarg; 2287196831Smav while (isspace(*tstr) && (*tstr != '\0')) 2288196831Smav tstr++; 2289196831Smav hook.argc = argc - optind; 2290196831Smav hook.argv = argv + optind; 2291196831Smav hook.got = 0; 2292196831Smav atacmd_len = buff_encode_visit(atacmd, sizeof(atacmd), tstr, 2293196831Smav iget, &hook); 2294196831Smav /* 2295196831Smav * Increment optind by the number of arguments the 2296196831Smav * encoding routine processed. After each call to 2297196831Smav * getopt(3), optind points to the argument that 2298196831Smav * getopt should process _next_. In this case, 2299196831Smav * that means it points to the first command string 2300196831Smav * argument, if there is one. Once we increment 2301196831Smav * this, it should point to either the next command 2302196831Smav * line argument, or it should be past the end of 2303196831Smav * the list. 2304196831Smav */ 2305196831Smav optind += hook.got; 2306196831Smav break; 230739214Sgibbs case 'c': 230839214Sgibbs tstr = optarg; 230939214Sgibbs while (isspace(*tstr) && (*tstr != '\0')) 231039214Sgibbs tstr++; 231139214Sgibbs hook.argc = argc - optind; 231239214Sgibbs hook.argv = argv + optind; 231339214Sgibbs hook.got = 0; 231447867Sken cdb_len = buff_encode_visit(cdb, sizeof(cdb), tstr, 231547867Sken iget, &hook); 231639214Sgibbs /* 231739214Sgibbs * Increment optind by the number of arguments the 231839214Sgibbs * encoding routine processed. After each call to 231939214Sgibbs * getopt(3), optind points to the argument that 232039214Sgibbs * getopt should process _next_. In this case, 232139214Sgibbs * that means it points to the first command string 232239214Sgibbs * argument, if there is one. Once we increment 232339214Sgibbs * this, it should point to either the next command 232439214Sgibbs * line argument, or it should be past the end of 232539214Sgibbs * the list. 232639214Sgibbs */ 232739214Sgibbs optind += hook.got; 232839214Sgibbs break; 2329207498Smav case 'd': 2330207498Smav dmacmd = 1; 2331207498Smav break; 2332207498Smav case 'f': 2333207498Smav fpdmacmd = 1; 2334207498Smav break; 233539214Sgibbs case 'i': 233639214Sgibbs if (arglist & CAM_ARG_CMD_OUT) { 233739214Sgibbs warnx("command must either be " 233839214Sgibbs "read or write, not both"); 233939214Sgibbs error = 1; 234039214Sgibbs goto scsicmd_bailout; 234139214Sgibbs } 234239214Sgibbs arglist |= CAM_ARG_CMD_IN; 234339214Sgibbs flags = CAM_DIR_IN; 234439214Sgibbs data_bytes = strtol(optarg, NULL, 0); 234539214Sgibbs if (data_bytes <= 0) { 234639214Sgibbs warnx("invalid number of input bytes %d", 234739214Sgibbs data_bytes); 234839214Sgibbs error = 1; 234939214Sgibbs goto scsicmd_bailout; 235039214Sgibbs } 235139214Sgibbs hook.argc = argc - optind; 235239214Sgibbs hook.argv = argv + optind; 235339214Sgibbs hook.got = 0; 235439214Sgibbs optind++; 235539214Sgibbs datastr = cget(&hook, NULL); 235639214Sgibbs /* 235739214Sgibbs * If the user supplied "-" instead of a format, he 235839214Sgibbs * wants the data to be written to stdout. 235939214Sgibbs */ 236039214Sgibbs if ((datastr != NULL) 236139214Sgibbs && (datastr[0] == '-')) 236239214Sgibbs fd_data = 1; 236339214Sgibbs 236439214Sgibbs data_ptr = (u_int8_t *)malloc(data_bytes); 236569471Sjedgar if (data_ptr == NULL) { 236669471Sjedgar warnx("can't malloc memory for data_ptr"); 236769471Sjedgar error = 1; 236869471Sjedgar goto scsicmd_bailout; 236969471Sjedgar } 237039214Sgibbs break; 237139214Sgibbs case 'o': 237239214Sgibbs if (arglist & CAM_ARG_CMD_IN) { 237339214Sgibbs warnx("command must either be " 237439214Sgibbs "read or write, not both"); 2375214321Smav error = 1; 237639214Sgibbs goto scsicmd_bailout; 237739214Sgibbs } 237839214Sgibbs arglist |= CAM_ARG_CMD_OUT; 237939214Sgibbs flags = CAM_DIR_OUT; 238039214Sgibbs data_bytes = strtol(optarg, NULL, 0); 238139214Sgibbs if (data_bytes <= 0) { 238239214Sgibbs warnx("invalid number of output bytes %d", 238339214Sgibbs data_bytes); 238439214Sgibbs error = 1; 238539214Sgibbs goto scsicmd_bailout; 238639214Sgibbs } 238739214Sgibbs hook.argc = argc - optind; 238839214Sgibbs hook.argv = argv + optind; 238939214Sgibbs hook.got = 0; 239039214Sgibbs datastr = cget(&hook, NULL); 239139214Sgibbs data_ptr = (u_int8_t *)malloc(data_bytes); 239269471Sjedgar if (data_ptr == NULL) { 239369471Sjedgar warnx("can't malloc memory for data_ptr"); 239469471Sjedgar error = 1; 239569471Sjedgar goto scsicmd_bailout; 239669471Sjedgar } 2397202694Smav bzero(data_ptr, data_bytes); 239839214Sgibbs /* 239939214Sgibbs * If the user supplied "-" instead of a format, he 240039214Sgibbs * wants the data to be read from stdin. 240139214Sgibbs */ 240239214Sgibbs if ((datastr != NULL) 240339214Sgibbs && (datastr[0] == '-')) 240439214Sgibbs fd_data = 1; 240539214Sgibbs else 240639214Sgibbs buff_encode_visit(data_ptr, data_bytes, datastr, 240739214Sgibbs iget, &hook); 240839214Sgibbs optind += hook.got; 240939214Sgibbs break; 2410196831Smav case 'r': 2411196831Smav need_res = 1; 2412196831Smav hook.argc = argc - optind; 2413196831Smav hook.argv = argv + optind; 2414196831Smav hook.got = 0; 2415196831Smav resstr = cget(&hook, NULL); 2416196831Smav if ((resstr != NULL) && (resstr[0] == '-')) 2417196831Smav fd_res = 1; 2418196831Smav optind += hook.got; 2419196831Smav break; 242039214Sgibbs default: 242139214Sgibbs break; 242239214Sgibbs } 242339214Sgibbs } 242439214Sgibbs 242539214Sgibbs /* 242639214Sgibbs * If fd_data is set, and we're writing to the device, we need to 242739214Sgibbs * read the data the user wants written from stdin. 242839214Sgibbs */ 242939214Sgibbs if ((fd_data == 1) && (arglist & CAM_ARG_CMD_OUT)) { 2430102192Sjohan ssize_t amt_read; 243139214Sgibbs int amt_to_read = data_bytes; 243239214Sgibbs u_int8_t *buf_ptr = data_ptr; 243339214Sgibbs 243439214Sgibbs for (amt_read = 0; amt_to_read > 0; 243580381Ssheldonh amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) { 243639214Sgibbs if (amt_read == -1) { 243739214Sgibbs warn("error reading data from stdin"); 243839214Sgibbs error = 1; 243939214Sgibbs goto scsicmd_bailout; 244039214Sgibbs } 244139214Sgibbs amt_to_read -= amt_read; 244239214Sgibbs buf_ptr += amt_read; 244339214Sgibbs } 244439214Sgibbs } 244539214Sgibbs 244639214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 244739214Sgibbs flags |= CAM_PASS_ERR_RECOVER; 244839214Sgibbs 244939214Sgibbs /* Disable freezing the device queue */ 245039214Sgibbs flags |= CAM_DEV_QFRZDIS; 245139214Sgibbs 2452196831Smav if (cdb_len) { 2453196831Smav /* 2454196831Smav * This is taken from the SCSI-3 draft spec. 2455196831Smav * (T10/1157D revision 0.3) 2456196831Smav * The top 3 bits of an opcode are the group code. 2457196831Smav * The next 5 bits are the command code. 2458196831Smav * Group 0: six byte commands 2459196831Smav * Group 1: ten byte commands 2460196831Smav * Group 2: ten byte commands 2461196831Smav * Group 3: reserved 2462196831Smav * Group 4: sixteen byte commands 2463196831Smav * Group 5: twelve byte commands 2464196831Smav * Group 6: vendor specific 2465196831Smav * Group 7: vendor specific 2466196831Smav */ 2467196831Smav switch((cdb[0] >> 5) & 0x7) { 2468196831Smav case 0: 2469196831Smav cdb_len = 6; 2470196831Smav break; 2471196831Smav case 1: 2472196831Smav case 2: 2473196831Smav cdb_len = 10; 2474196831Smav break; 2475196831Smav case 3: 2476196831Smav case 6: 2477196831Smav case 7: 2478196831Smav /* computed by buff_encode_visit */ 2479196831Smav break; 2480196831Smav case 4: 2481196831Smav cdb_len = 16; 2482196831Smav break; 2483196831Smav case 5: 2484196831Smav cdb_len = 12; 2485196831Smav break; 2486196831Smav } 248739214Sgibbs 2488196831Smav /* 2489196831Smav * We should probably use csio_build_visit or something like that 2490196831Smav * here, but it's easier to encode arguments as you go. The 2491196831Smav * alternative would be skipping the CDB argument and then encoding 2492196831Smav * it here, since we've got the data buffer argument by now. 2493196831Smav */ 2494196831Smav bcopy(cdb, &ccb->csio.cdb_io.cdb_bytes, cdb_len); 249539214Sgibbs 2496196831Smav cam_fill_csio(&ccb->csio, 249739214Sgibbs /*retries*/ retry_count, 249839214Sgibbs /*cbfcnp*/ NULL, 249939214Sgibbs /*flags*/ flags, 250039214Sgibbs /*tag_action*/ MSG_SIMPLE_Q_TAG, 250139214Sgibbs /*data_ptr*/ data_ptr, 250239214Sgibbs /*dxfer_len*/ data_bytes, 250339214Sgibbs /*sense_len*/ SSD_FULL_SIZE, 250439214Sgibbs /*cdb_len*/ cdb_len, 250539214Sgibbs /*timeout*/ timeout ? timeout : 5000); 2506196831Smav } else { 2507196831Smav atacmd_len = 12; 2508196831Smav bcopy(atacmd, &ccb->ataio.cmd.command, atacmd_len); 2509196831Smav if (need_res) 2510196831Smav ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT; 2511207498Smav if (dmacmd) 2512207498Smav ccb->ataio.cmd.flags |= CAM_ATAIO_DMA; 2513207498Smav if (fpdmacmd) 2514207498Smav ccb->ataio.cmd.flags |= CAM_ATAIO_FPDMA; 251539214Sgibbs 2516196831Smav cam_fill_ataio(&ccb->ataio, 2517196831Smav /*retries*/ retry_count, 2518196831Smav /*cbfcnp*/ NULL, 2519196831Smav /*flags*/ flags, 2520196831Smav /*tag_action*/ 0, 2521196831Smav /*data_ptr*/ data_ptr, 2522196831Smav /*dxfer_len*/ data_bytes, 2523196831Smav /*timeout*/ timeout ? timeout : 5000); 2524196831Smav } 2525196831Smav 252639214Sgibbs if (((retval = cam_send_ccb(device, ccb)) < 0) 252739214Sgibbs || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 2528228602Sdim const char warnstr[] = "error sending command"; 2529216088Sken 253039214Sgibbs if (retval < 0) 2531216088Sken warn(warnstr); 253239214Sgibbs else 2533216088Sken warnx(warnstr); 253439214Sgibbs 253539214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 253674840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 253774840Sken CAM_EPF_ALL, stderr); 253839214Sgibbs } 253939214Sgibbs 254039214Sgibbs error = 1; 254139214Sgibbs goto scsicmd_bailout; 254239214Sgibbs } 254339214Sgibbs 2544196831Smav if (atacmd_len && need_res) { 2545196831Smav if (fd_res == 0) { 2546196831Smav buff_decode_visit(&ccb->ataio.res.status, 11, resstr, 2547196831Smav arg_put, NULL); 2548196831Smav fprintf(stdout, "\n"); 2549196831Smav } else { 2550196831Smav fprintf(stdout, 2551196831Smav "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", 2552196831Smav ccb->ataio.res.status, 2553196831Smav ccb->ataio.res.error, 2554196831Smav ccb->ataio.res.lba_low, 2555196831Smav ccb->ataio.res.lba_mid, 2556196831Smav ccb->ataio.res.lba_high, 2557196831Smav ccb->ataio.res.device, 2558196831Smav ccb->ataio.res.lba_low_exp, 2559196831Smav ccb->ataio.res.lba_mid_exp, 2560196831Smav ccb->ataio.res.lba_high_exp, 2561196831Smav ccb->ataio.res.sector_count, 2562196831Smav ccb->ataio.res.sector_count_exp); 2563196831Smav fflush(stdout); 2564196831Smav } 2565196831Smav } 256639214Sgibbs 256739214Sgibbs if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 256839214Sgibbs && (arglist & CAM_ARG_CMD_IN) 256939214Sgibbs && (data_bytes > 0)) { 257039214Sgibbs if (fd_data == 0) { 257139214Sgibbs buff_decode_visit(data_ptr, data_bytes, datastr, 257239214Sgibbs arg_put, NULL); 257339214Sgibbs fprintf(stdout, "\n"); 257439214Sgibbs } else { 2575102192Sjohan ssize_t amt_written; 257639214Sgibbs int amt_to_write = data_bytes; 257739214Sgibbs u_int8_t *buf_ptr = data_ptr; 257839214Sgibbs 257939214Sgibbs for (amt_written = 0; (amt_to_write > 0) && 258039214Sgibbs (amt_written =write(1, buf_ptr,amt_to_write))> 0;){ 258139214Sgibbs amt_to_write -= amt_written; 258239214Sgibbs buf_ptr += amt_written; 258339214Sgibbs } 258439214Sgibbs if (amt_written == -1) { 258539214Sgibbs warn("error writing data to stdout"); 258639214Sgibbs error = 1; 258739214Sgibbs goto scsicmd_bailout; 258839214Sgibbs } else if ((amt_written == 0) 258939214Sgibbs && (amt_to_write > 0)) { 259039214Sgibbs warnx("only wrote %u bytes out of %u", 259139214Sgibbs data_bytes - amt_to_write, data_bytes); 259239214Sgibbs } 259339214Sgibbs } 259439214Sgibbs } 259539214Sgibbs 259639214Sgibbsscsicmd_bailout: 259739214Sgibbs 259839214Sgibbs if ((data_bytes > 0) && (data_ptr != NULL)) 259939214Sgibbs free(data_ptr); 260039214Sgibbs 260139214Sgibbs cam_freeccb(ccb); 260239214Sgibbs 260339214Sgibbs return(error); 260439214Sgibbs} 260539214Sgibbs 260639214Sgibbsstatic int 260739214Sgibbscamdebug(int argc, char **argv, char *combinedopt) 260839214Sgibbs{ 260939214Sgibbs int c, fd; 261039214Sgibbs int bus = -1, target = -1, lun = -1; 261139214Sgibbs char *tstr, *tmpstr = NULL; 261239214Sgibbs union ccb ccb; 261339214Sgibbs int error = 0; 261439214Sgibbs 261539214Sgibbs bzero(&ccb, sizeof(union ccb)); 261639214Sgibbs 261739214Sgibbs while ((c = getopt(argc, argv, combinedopt)) != -1) { 261839214Sgibbs switch(c) { 261939214Sgibbs case 'I': 262039214Sgibbs arglist |= CAM_ARG_DEBUG_INFO; 262139214Sgibbs ccb.cdbg.flags |= CAM_DEBUG_INFO; 262239214Sgibbs break; 2623107966Snjl case 'P': 2624107966Snjl arglist |= CAM_ARG_DEBUG_PERIPH; 2625107966Snjl ccb.cdbg.flags |= CAM_DEBUG_PERIPH; 2626107966Snjl break; 262752541Sluoqi case 'S': 262852541Sluoqi arglist |= CAM_ARG_DEBUG_SUBTRACE; 262952541Sluoqi ccb.cdbg.flags |= CAM_DEBUG_SUBTRACE; 263052541Sluoqi break; 263152535Sluoqi case 'T': 263239214Sgibbs arglist |= CAM_ARG_DEBUG_TRACE; 263339214Sgibbs ccb.cdbg.flags |= CAM_DEBUG_TRACE; 263439214Sgibbs break; 2635107966Snjl case 'X': 2636107966Snjl arglist |= CAM_ARG_DEBUG_XPT; 2637107966Snjl ccb.cdbg.flags |= CAM_DEBUG_XPT; 2638107966Snjl break; 263939903Sken case 'c': 264039903Sken arglist |= CAM_ARG_DEBUG_CDB; 264139903Sken ccb.cdbg.flags |= CAM_DEBUG_CDB; 264239903Sken break; 264339214Sgibbs default: 264439214Sgibbs break; 264539214Sgibbs } 264639214Sgibbs } 264739214Sgibbs 264839214Sgibbs if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { 264939214Sgibbs warnx("error opening transport layer device %s", XPT_DEVICE); 265039214Sgibbs warn("%s", XPT_DEVICE); 265139214Sgibbs return(1); 265239214Sgibbs } 265339214Sgibbs argc -= optind; 265439214Sgibbs argv += optind; 265539214Sgibbs 265639214Sgibbs if (argc <= 0) { 265739214Sgibbs warnx("you must specify \"off\", \"all\" or a bus,"); 265839214Sgibbs warnx("bus:target, or bus:target:lun"); 265939214Sgibbs close(fd); 266039214Sgibbs return(1); 266139214Sgibbs } 266239214Sgibbs 266339214Sgibbs tstr = *argv; 266439214Sgibbs 266539214Sgibbs while (isspace(*tstr) && (*tstr != '\0')) 266639214Sgibbs tstr++; 266739214Sgibbs 266839214Sgibbs if (strncmp(tstr, "off", 3) == 0) { 266939214Sgibbs ccb.cdbg.flags = CAM_DEBUG_NONE; 2670107966Snjl arglist &= ~(CAM_ARG_DEBUG_INFO|CAM_ARG_DEBUG_PERIPH| 2671107966Snjl CAM_ARG_DEBUG_TRACE|CAM_ARG_DEBUG_SUBTRACE| 2672107966Snjl CAM_ARG_DEBUG_XPT); 267339214Sgibbs } else if (strncmp(tstr, "all", 3) != 0) { 267439214Sgibbs tmpstr = (char *)strtok(tstr, ":"); 267539214Sgibbs if ((tmpstr != NULL) && (*tmpstr != '\0')){ 267639214Sgibbs bus = strtol(tmpstr, NULL, 0); 267739214Sgibbs arglist |= CAM_ARG_BUS; 267839214Sgibbs tmpstr = (char *)strtok(NULL, ":"); 267939214Sgibbs if ((tmpstr != NULL) && (*tmpstr != '\0')){ 268039214Sgibbs target = strtol(tmpstr, NULL, 0); 268139214Sgibbs arglist |= CAM_ARG_TARGET; 268239214Sgibbs tmpstr = (char *)strtok(NULL, ":"); 268339214Sgibbs if ((tmpstr != NULL) && (*tmpstr != '\0')){ 268439214Sgibbs lun = strtol(tmpstr, NULL, 0); 268539214Sgibbs arglist |= CAM_ARG_LUN; 268639214Sgibbs } 268739214Sgibbs } 268839214Sgibbs } else { 268939214Sgibbs error = 1; 269039214Sgibbs warnx("you must specify \"all\", \"off\", or a bus,"); 269139214Sgibbs warnx("bus:target, or bus:target:lun to debug"); 269239214Sgibbs } 269339214Sgibbs } 2694214321Smav 269539214Sgibbs if (error == 0) { 269639214Sgibbs 269739214Sgibbs ccb.ccb_h.func_code = XPT_DEBUG; 269839214Sgibbs ccb.ccb_h.path_id = bus; 269939214Sgibbs ccb.ccb_h.target_id = target; 270039214Sgibbs ccb.ccb_h.target_lun = lun; 270139214Sgibbs 270239214Sgibbs if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 270339214Sgibbs warn("CAMIOCOMMAND ioctl failed"); 270439214Sgibbs error = 1; 270539214Sgibbs } 270639214Sgibbs 270739214Sgibbs if (error == 0) { 270839214Sgibbs if ((ccb.ccb_h.status & CAM_STATUS_MASK) == 270939214Sgibbs CAM_FUNC_NOTAVAIL) { 271039214Sgibbs warnx("CAM debugging not available"); 271139214Sgibbs warnx("you need to put options CAMDEBUG in" 271239214Sgibbs " your kernel config file!"); 271339214Sgibbs error = 1; 271439214Sgibbs } else if ((ccb.ccb_h.status & CAM_STATUS_MASK) != 271539214Sgibbs CAM_REQ_CMP) { 271639214Sgibbs warnx("XPT_DEBUG CCB failed with status %#x", 271739214Sgibbs ccb.ccb_h.status); 271839214Sgibbs error = 1; 271939214Sgibbs } else { 272039214Sgibbs if (ccb.cdbg.flags == CAM_DEBUG_NONE) { 272139214Sgibbs fprintf(stderr, 272239214Sgibbs "Debugging turned off\n"); 272339214Sgibbs } else { 272439214Sgibbs fprintf(stderr, 272539214Sgibbs "Debugging enabled for " 272639214Sgibbs "%d:%d:%d\n", 272739214Sgibbs bus, target, lun); 272839214Sgibbs } 272939214Sgibbs } 273039214Sgibbs } 273139903Sken close(fd); 273239214Sgibbs } 273339214Sgibbs 273439214Sgibbs return(error); 273539214Sgibbs} 273639214Sgibbs 273746581Skenstatic int 273846581Skentagcontrol(struct cam_device *device, int argc, char **argv, 273946581Sken char *combinedopt) 274046581Sken{ 274146581Sken int c; 274246581Sken union ccb *ccb; 274346581Sken int numtags = -1; 274446581Sken int retval = 0; 274546581Sken int quiet = 0; 274646581Sken char pathstr[1024]; 274746581Sken 274846581Sken ccb = cam_getccb(device); 274946581Sken 275046581Sken if (ccb == NULL) { 275146581Sken warnx("tagcontrol: error allocating ccb"); 275246581Sken return(1); 275346581Sken } 275446581Sken 275546581Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 275646581Sken switch(c) { 275746581Sken case 'N': 275846581Sken numtags = strtol(optarg, NULL, 0); 275946581Sken if (numtags < 0) { 276046581Sken warnx("tag count %d is < 0", numtags); 276146581Sken retval = 1; 276246581Sken goto tagcontrol_bailout; 276346581Sken } 276446581Sken break; 276546581Sken case 'q': 276646581Sken quiet++; 276746581Sken break; 276846581Sken default: 276946581Sken break; 277046581Sken } 277146581Sken } 277246581Sken 277346581Sken cam_path_string(device, pathstr, sizeof(pathstr)); 277446581Sken 277546581Sken if (numtags >= 0) { 277646581Sken bzero(&(&ccb->ccb_h)[1], 277746581Sken sizeof(struct ccb_relsim) - sizeof(struct ccb_hdr)); 277846581Sken ccb->ccb_h.func_code = XPT_REL_SIMQ; 2779220887Smav ccb->ccb_h.flags = CAM_DEV_QFREEZE; 278046581Sken ccb->crs.release_flags = RELSIM_ADJUST_OPENINGS; 278146581Sken ccb->crs.openings = numtags; 278246581Sken 278346581Sken 278446581Sken if (cam_send_ccb(device, ccb) < 0) { 278546581Sken perror("error sending XPT_REL_SIMQ CCB"); 278646581Sken retval = 1; 278746581Sken goto tagcontrol_bailout; 278846581Sken } 278946581Sken 279046581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 279174840Sken warnx("XPT_REL_SIMQ CCB failed"); 279274840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 279374840Sken CAM_EPF_ALL, stderr); 279446581Sken retval = 1; 279546581Sken goto tagcontrol_bailout; 279646581Sken } 279746581Sken 279846581Sken 279946581Sken if (quiet == 0) 280046581Sken fprintf(stdout, "%stagged openings now %d\n", 280146581Sken pathstr, ccb->crs.openings); 280246581Sken } 280346581Sken 280446581Sken bzero(&(&ccb->ccb_h)[1], 280593501Sken sizeof(struct ccb_getdevstats) - sizeof(struct ccb_hdr)); 280646581Sken 280756121Smjacob ccb->ccb_h.func_code = XPT_GDEV_STATS; 280846581Sken 280946581Sken if (cam_send_ccb(device, ccb) < 0) { 281056121Smjacob perror("error sending XPT_GDEV_STATS CCB"); 281146581Sken retval = 1; 281246581Sken goto tagcontrol_bailout; 281346581Sken } 281446581Sken 281546581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 281674840Sken warnx("XPT_GDEV_STATS CCB failed"); 281774840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 281874840Sken CAM_EPF_ALL, stderr); 281946581Sken retval = 1; 282046581Sken goto tagcontrol_bailout; 282146581Sken } 282246581Sken 282346581Sken if (arglist & CAM_ARG_VERBOSE) { 282446581Sken fprintf(stdout, "%s", pathstr); 282556121Smjacob fprintf(stdout, "dev_openings %d\n", ccb->cgds.dev_openings); 282646581Sken fprintf(stdout, "%s", pathstr); 282756121Smjacob fprintf(stdout, "dev_active %d\n", ccb->cgds.dev_active); 282846581Sken fprintf(stdout, "%s", pathstr); 282956121Smjacob fprintf(stdout, "devq_openings %d\n", ccb->cgds.devq_openings); 283046581Sken fprintf(stdout, "%s", pathstr); 283156121Smjacob fprintf(stdout, "devq_queued %d\n", ccb->cgds.devq_queued); 283246581Sken fprintf(stdout, "%s", pathstr); 283356121Smjacob fprintf(stdout, "held %d\n", ccb->cgds.held); 283446581Sken fprintf(stdout, "%s", pathstr); 283556121Smjacob fprintf(stdout, "mintags %d\n", ccb->cgds.mintags); 283646581Sken fprintf(stdout, "%s", pathstr); 283756121Smjacob fprintf(stdout, "maxtags %d\n", ccb->cgds.maxtags); 283846581Sken } else { 283946581Sken if (quiet == 0) { 284046581Sken fprintf(stdout, "%s", pathstr); 284146581Sken fprintf(stdout, "device openings: "); 284246581Sken } 284356121Smjacob fprintf(stdout, "%d\n", ccb->cgds.dev_openings + 284456121Smjacob ccb->cgds.dev_active); 284546581Sken } 284646581Sken 284746581Skentagcontrol_bailout: 284846581Sken 284946581Sken cam_freeccb(ccb); 285046581Sken return(retval); 285146581Sken} 285246581Sken 285346581Skenstatic void 285446581Skencts_print(struct cam_device *device, struct ccb_trans_settings *cts) 285546581Sken{ 285646581Sken char pathstr[1024]; 285746581Sken 285846581Sken cam_path_string(device, pathstr, sizeof(pathstr)); 285946581Sken 2860163896Smjacob if (cts->transport == XPORT_SPI) { 2861163896Smjacob struct ccb_trans_settings_spi *spi = 2862163896Smjacob &cts->xport_specific.spi; 286346581Sken 2864163896Smjacob if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) { 286546581Sken 2866163896Smjacob fprintf(stdout, "%ssync parameter: %d\n", pathstr, 2867163896Smjacob spi->sync_period); 286846581Sken 2869163896Smjacob if (spi->sync_offset != 0) { 2870163896Smjacob u_int freq; 2871163896Smjacob 2872163896Smjacob freq = scsi_calc_syncsrate(spi->sync_period); 2873163896Smjacob fprintf(stdout, "%sfrequency: %d.%03dMHz\n", 2874163896Smjacob pathstr, freq / 1000, freq % 1000); 2875163896Smjacob } 287646581Sken } 287746581Sken 2878163896Smjacob if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) { 2879163896Smjacob fprintf(stdout, "%soffset: %d\n", pathstr, 2880163896Smjacob spi->sync_offset); 2881163896Smjacob } 288246581Sken 2883163896Smjacob if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) { 2884163896Smjacob fprintf(stdout, "%sbus width: %d bits\n", pathstr, 2885163896Smjacob (0x01 << spi->bus_width) * 8); 2886163896Smjacob } 288746581Sken 2888163896Smjacob if (spi->valid & CTS_SPI_VALID_DISC) { 2889163896Smjacob fprintf(stdout, "%sdisconnection is %s\n", pathstr, 2890163896Smjacob (spi->flags & CTS_SPI_FLAGS_DISC_ENB) ? 2891163896Smjacob "enabled" : "disabled"); 2892163896Smjacob } 2893163896Smjacob } 2894236437Smav if (cts->transport == XPORT_FC) { 2895236437Smav struct ccb_trans_settings_fc *fc = 2896236437Smav &cts->xport_specific.fc; 2897236437Smav 2898236437Smav if (fc->valid & CTS_FC_VALID_WWNN) 2899236437Smav fprintf(stdout, "%sWWNN: 0x%llx", pathstr, 2900236437Smav (long long) fc->wwnn); 2901236437Smav if (fc->valid & CTS_FC_VALID_WWPN) 2902236437Smav fprintf(stdout, "%sWWPN: 0x%llx", pathstr, 2903236437Smav (long long) fc->wwpn); 2904236437Smav if (fc->valid & CTS_FC_VALID_PORT) 2905236437Smav fprintf(stdout, "%sPortID: 0x%x", pathstr, fc->port); 2906236437Smav if (fc->valid & CTS_FC_VALID_SPEED) 2907236437Smav fprintf(stdout, "%stransfer speed: %d.%03dMB/s\n", 2908236437Smav pathstr, fc->bitrate / 1000, fc->bitrate % 1000); 2909236437Smav } 2910236437Smav if (cts->transport == XPORT_SAS) { 2911236437Smav struct ccb_trans_settings_sas *sas = 2912236437Smav &cts->xport_specific.sas; 2913236437Smav 2914236437Smav if (sas->valid & CTS_SAS_VALID_SPEED) 2915236437Smav fprintf(stdout, "%stransfer speed: %d.%03dMB/s\n", 2916236437Smav pathstr, sas->bitrate / 1000, sas->bitrate % 1000); 2917236437Smav } 2918199747Smav if (cts->transport == XPORT_ATA) { 2919236437Smav struct ccb_trans_settings_pata *pata = 2920199747Smav &cts->xport_specific.ata; 292146581Sken 2922236437Smav if ((pata->valid & CTS_ATA_VALID_MODE) != 0) { 2923199747Smav fprintf(stdout, "%sATA mode: %s\n", pathstr, 2924236437Smav ata_mode2string(pata->mode)); 2925199747Smav } 2926236437Smav if ((pata->valid & CTS_ATA_VALID_ATAPI) != 0) { 2927203376Smav fprintf(stdout, "%sATAPI packet length: %d\n", pathstr, 2928236437Smav pata->atapi); 2929203376Smav } 2930236437Smav if ((pata->valid & CTS_ATA_VALID_BYTECOUNT) != 0) { 2931199747Smav fprintf(stdout, "%sPIO transaction length: %d\n", 2932236437Smav pathstr, pata->bytecount); 2933199747Smav } 2934199747Smav } 2935199747Smav if (cts->transport == XPORT_SATA) { 2936199747Smav struct ccb_trans_settings_sata *sata = 2937199747Smav &cts->xport_specific.sata; 2938199747Smav 2939199747Smav if ((sata->valid & CTS_SATA_VALID_REVISION) != 0) { 2940199747Smav fprintf(stdout, "%sSATA revision: %d.x\n", pathstr, 2941199747Smav sata->revision); 2942199747Smav } 2943199747Smav if ((sata->valid & CTS_SATA_VALID_MODE) != 0) { 2944199747Smav fprintf(stdout, "%sATA mode: %s\n", pathstr, 2945199747Smav ata_mode2string(sata->mode)); 2946199747Smav } 2947203376Smav if ((sata->valid & CTS_SATA_VALID_ATAPI) != 0) { 2948203376Smav fprintf(stdout, "%sATAPI packet length: %d\n", pathstr, 2949203376Smav sata->atapi); 2950203376Smav } 2951199747Smav if ((sata->valid & CTS_SATA_VALID_BYTECOUNT) != 0) { 2952199747Smav fprintf(stdout, "%sPIO transaction length: %d\n", 2953199747Smav pathstr, sata->bytecount); 2954199747Smav } 2955199747Smav if ((sata->valid & CTS_SATA_VALID_PM) != 0) { 2956199747Smav fprintf(stdout, "%sPMP presence: %d\n", pathstr, 2957199747Smav sata->pm_present); 2958199747Smav } 2959199747Smav if ((sata->valid & CTS_SATA_VALID_TAGS) != 0) { 2960199747Smav fprintf(stdout, "%sNumber of tags: %d\n", pathstr, 2961199747Smav sata->tags); 2962199747Smav } 2963207499Smav if ((sata->valid & CTS_SATA_VALID_CAPS) != 0) { 2964207499Smav fprintf(stdout, "%sSATA capabilities: %08x\n", pathstr, 2965207499Smav sata->caps); 2966207499Smav } 2967199747Smav } 2968236437Smav if (cts->protocol == PROTO_ATA) { 2969236437Smav struct ccb_trans_settings_ata *ata= 2970236437Smav &cts->proto_specific.ata; 2971236437Smav 2972236437Smav if (ata->valid & CTS_ATA_VALID_TQ) { 2973236437Smav fprintf(stdout, "%stagged queueing: %s\n", pathstr, 2974236437Smav (ata->flags & CTS_ATA_FLAGS_TAG_ENB) ? 2975236437Smav "enabled" : "disabled"); 2976236437Smav } 2977236437Smav } 2978163896Smjacob if (cts->protocol == PROTO_SCSI) { 2979163896Smjacob struct ccb_trans_settings_scsi *scsi= 2980163896Smjacob &cts->proto_specific.scsi; 298146581Sken 2982163896Smjacob if (scsi->valid & CTS_SCSI_VALID_TQ) { 2983236437Smav fprintf(stdout, "%stagged queueing: %s\n", pathstr, 2984163896Smjacob (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) ? 2985163896Smjacob "enabled" : "disabled"); 2986163896Smjacob } 2987163896Smjacob } 2988163896Smjacob 298946581Sken} 299046581Sken 299146581Sken/* 2992214321Smav * Get a path inquiry CCB for the specified device. 299346581Sken */ 299446581Skenstatic int 299546581Skenget_cpi(struct cam_device *device, struct ccb_pathinq *cpi) 299646581Sken{ 299746581Sken union ccb *ccb; 299846581Sken int retval = 0; 299946581Sken 300046581Sken ccb = cam_getccb(device); 300146581Sken if (ccb == NULL) { 300246581Sken warnx("get_cpi: couldn't allocate CCB"); 300346581Sken return(1); 300446581Sken } 300546581Sken bzero(&(&ccb->ccb_h)[1], 300646581Sken sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr)); 300746581Sken ccb->ccb_h.func_code = XPT_PATH_INQ; 300846581Sken if (cam_send_ccb(device, ccb) < 0) { 300946581Sken warn("get_cpi: error sending Path Inquiry CCB"); 301046581Sken if (arglist & CAM_ARG_VERBOSE) 301174840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 301274840Sken CAM_EPF_ALL, stderr); 301346581Sken retval = 1; 301446581Sken goto get_cpi_bailout; 301546581Sken } 301646581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 301746581Sken if (arglist & CAM_ARG_VERBOSE) 301874840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 301974840Sken CAM_EPF_ALL, stderr); 302046581Sken retval = 1; 302146581Sken goto get_cpi_bailout; 302246581Sken } 302346581Sken bcopy(&ccb->cpi, cpi, sizeof(struct ccb_pathinq)); 302446581Sken 302546581Skenget_cpi_bailout: 3026196658Smav cam_freeccb(ccb); 3027196658Smav return(retval); 3028196658Smav} 302946581Sken 3030196658Smav/* 3031214321Smav * Get a get device CCB for the specified device. 3032196658Smav */ 3033196658Smavstatic int 3034196658Smavget_cgd(struct cam_device *device, struct ccb_getdev *cgd) 3035196658Smav{ 3036196658Smav union ccb *ccb; 3037196658Smav int retval = 0; 3038196658Smav 3039196658Smav ccb = cam_getccb(device); 3040196658Smav if (ccb == NULL) { 3041196658Smav warnx("get_cgd: couldn't allocate CCB"); 3042196658Smav return(1); 3043196658Smav } 3044196658Smav bzero(&(&ccb->ccb_h)[1], 3045196658Smav sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr)); 3046196658Smav ccb->ccb_h.func_code = XPT_GDEV_TYPE; 3047196658Smav if (cam_send_ccb(device, ccb) < 0) { 3048196658Smav warn("get_cgd: error sending Path Inquiry CCB"); 3049196658Smav if (arglist & CAM_ARG_VERBOSE) 3050196658Smav cam_error_print(device, ccb, CAM_ESF_ALL, 3051196658Smav CAM_EPF_ALL, stderr); 3052196658Smav retval = 1; 3053196658Smav goto get_cgd_bailout; 3054196658Smav } 3055196658Smav if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 3056196658Smav if (arglist & CAM_ARG_VERBOSE) 3057196658Smav cam_error_print(device, ccb, CAM_ESF_ALL, 3058196658Smav CAM_EPF_ALL, stderr); 3059196658Smav retval = 1; 3060196658Smav goto get_cgd_bailout; 3061196658Smav } 3062196658Smav bcopy(&ccb->cgd, cgd, sizeof(struct ccb_getdev)); 3063196658Smav 3064196658Smavget_cgd_bailout: 306546581Sken cam_freeccb(ccb); 306646581Sken return(retval); 306746581Sken} 306846581Sken 306946581Skenstatic void 307046581Skencpi_print(struct ccb_pathinq *cpi) 307146581Sken{ 307246581Sken char adapter_str[1024]; 307346581Sken int i; 307446581Sken 307546581Sken snprintf(adapter_str, sizeof(adapter_str), 307646581Sken "%s%d:", cpi->dev_name, cpi->unit_number); 307746581Sken 307846581Sken fprintf(stdout, "%s SIM/HBA version: %d\n", adapter_str, 307946581Sken cpi->version_num); 308046581Sken 308146581Sken for (i = 1; i < 0xff; i = i << 1) { 3082118478Sjohan const char *str; 308346581Sken 308446581Sken if ((i & cpi->hba_inquiry) == 0) 308546581Sken continue; 308646581Sken 308746581Sken fprintf(stdout, "%s supports ", adapter_str); 308846581Sken 308946581Sken switch(i) { 309046581Sken case PI_MDP_ABLE: 309146581Sken str = "MDP message"; 309246581Sken break; 309346581Sken case PI_WIDE_32: 309446581Sken str = "32 bit wide SCSI"; 309546581Sken break; 309646581Sken case PI_WIDE_16: 309746581Sken str = "16 bit wide SCSI"; 309846581Sken break; 309946581Sken case PI_SDTR_ABLE: 310046581Sken str = "SDTR message"; 310146581Sken break; 310246581Sken case PI_LINKED_CDB: 310346581Sken str = "linked CDBs"; 310446581Sken break; 310546581Sken case PI_TAG_ABLE: 310646581Sken str = "tag queue messages"; 310746581Sken break; 310846581Sken case PI_SOFT_RST: 310946581Sken str = "soft reset alternative"; 311046581Sken break; 3111196658Smav case PI_SATAPM: 3112196658Smav str = "SATA Port Multiplier"; 3113196658Smav break; 311451691Sbillf default: 311551691Sbillf str = "unknown PI bit set"; 311651691Sbillf break; 311746581Sken } 311846581Sken fprintf(stdout, "%s\n", str); 311946581Sken } 312046581Sken 312146581Sken for (i = 1; i < 0xff; i = i << 1) { 3122118478Sjohan const char *str; 312346581Sken 312446581Sken if ((i & cpi->hba_misc) == 0) 312546581Sken continue; 312646581Sken 312746581Sken fprintf(stdout, "%s ", adapter_str); 312846581Sken 312946581Sken switch(i) { 313046581Sken case PIM_SCANHILO: 313146581Sken str = "bus scans from high ID to low ID"; 313246581Sken break; 313346581Sken case PIM_NOREMOVE: 313446581Sken str = "removable devices not included in scan"; 313546581Sken break; 313646581Sken case PIM_NOINITIATOR: 313746581Sken str = "initiator role not supported"; 313846581Sken break; 313946581Sken case PIM_NOBUSRESET: 314046581Sken str = "user has disabled initial BUS RESET or" 314146581Sken " controller is in target/mixed mode"; 314246581Sken break; 3143196658Smav case PIM_NO_6_BYTE: 3144196658Smav str = "do not send 6-byte commands"; 3145196658Smav break; 3146196658Smav case PIM_SEQSCAN: 3147196658Smav str = "scan bus sequentially"; 3148196658Smav break; 314951691Sbillf default: 315051691Sbillf str = "unknown PIM bit set"; 315151691Sbillf break; 315246581Sken } 315346581Sken fprintf(stdout, "%s\n", str); 315446581Sken } 315546581Sken 315646581Sken for (i = 1; i < 0xff; i = i << 1) { 3157118478Sjohan const char *str; 315846581Sken 315946581Sken if ((i & cpi->target_sprt) == 0) 316046581Sken continue; 316146581Sken 316246581Sken fprintf(stdout, "%s supports ", adapter_str); 316346581Sken switch(i) { 316446581Sken case PIT_PROCESSOR: 316546581Sken str = "target mode processor mode"; 316646581Sken break; 316746581Sken case PIT_PHASE: 316846581Sken str = "target mode phase cog. mode"; 316946581Sken break; 317046581Sken case PIT_DISCONNECT: 317146581Sken str = "disconnects in target mode"; 317246581Sken break; 317346581Sken case PIT_TERM_IO: 317446581Sken str = "terminate I/O message in target mode"; 317546581Sken break; 317646581Sken case PIT_GRP_6: 317746581Sken str = "group 6 commands in target mode"; 317846581Sken break; 317946581Sken case PIT_GRP_7: 318046581Sken str = "group 7 commands in target mode"; 318146581Sken break; 318251691Sbillf default: 318351691Sbillf str = "unknown PIT bit set"; 318451691Sbillf break; 318546581Sken } 318646581Sken 318746581Sken fprintf(stdout, "%s\n", str); 318846581Sken } 318946581Sken fprintf(stdout, "%s HBA engine count: %d\n", adapter_str, 319046581Sken cpi->hba_eng_cnt); 319156985Sken fprintf(stdout, "%s maximum target: %d\n", adapter_str, 319246581Sken cpi->max_target); 319356985Sken fprintf(stdout, "%s maximum LUN: %d\n", adapter_str, 319446581Sken cpi->max_lun); 319546581Sken fprintf(stdout, "%s highest path ID in subsystem: %d\n", 319646581Sken adapter_str, cpi->hpath_id); 319766003Sken fprintf(stdout, "%s initiator ID: %d\n", adapter_str, 319866003Sken cpi->initiator_id); 319946581Sken fprintf(stdout, "%s SIM vendor: %s\n", adapter_str, cpi->sim_vid); 320046581Sken fprintf(stdout, "%s HBA vendor: %s\n", adapter_str, cpi->hba_vid); 3201210471Smav fprintf(stdout, "%s HBA vendor ID: 0x%04x\n", 3202210471Smav adapter_str, cpi->hba_vendor); 3203210471Smav fprintf(stdout, "%s HBA device ID: 0x%04x\n", 3204210471Smav adapter_str, cpi->hba_device); 3205210471Smav fprintf(stdout, "%s HBA subvendor ID: 0x%04x\n", 3206210471Smav adapter_str, cpi->hba_subvendor); 3207210471Smav fprintf(stdout, "%s HBA subdevice ID: 0x%04x\n", 3208210471Smav adapter_str, cpi->hba_subdevice); 320946581Sken fprintf(stdout, "%s bus ID: %d\n", adapter_str, cpi->bus_id); 321046581Sken fprintf(stdout, "%s base transfer speed: ", adapter_str); 321146581Sken if (cpi->base_transfer_speed > 1000) 321246581Sken fprintf(stdout, "%d.%03dMB/sec\n", 321346581Sken cpi->base_transfer_speed / 1000, 321446581Sken cpi->base_transfer_speed % 1000); 321546581Sken else 321646581Sken fprintf(stdout, "%dKB/sec\n", 321746581Sken (cpi->base_transfer_speed % 1000) * 1000); 3218210471Smav fprintf(stdout, "%s maximum transfer size: %u bytes\n", 3219210471Smav adapter_str, cpi->maxio); 322046581Sken} 322146581Sken 322246581Skenstatic int 322346581Skenget_print_cts(struct cam_device *device, int user_settings, int quiet, 322446581Sken struct ccb_trans_settings *cts) 322546581Sken{ 322646581Sken int retval; 322746581Sken union ccb *ccb; 322846581Sken 322946581Sken retval = 0; 323046581Sken ccb = cam_getccb(device); 323146581Sken 323246581Sken if (ccb == NULL) { 323346581Sken warnx("get_print_cts: error allocating ccb"); 323446581Sken return(1); 323546581Sken } 323646581Sken 323746581Sken bzero(&(&ccb->ccb_h)[1], 323846581Sken sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr)); 323946581Sken 324046581Sken ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 324146581Sken 324246581Sken if (user_settings == 0) 3243163896Smjacob ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS; 324446581Sken else 3245163896Smjacob ccb->cts.type = CTS_TYPE_USER_SETTINGS; 324646581Sken 324746581Sken if (cam_send_ccb(device, ccb) < 0) { 324846581Sken perror("error sending XPT_GET_TRAN_SETTINGS CCB"); 324974840Sken if (arglist & CAM_ARG_VERBOSE) 325074840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 325174840Sken CAM_EPF_ALL, stderr); 325246581Sken retval = 1; 325346581Sken goto get_print_cts_bailout; 325446581Sken } 325546581Sken 325646581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 325774840Sken warnx("XPT_GET_TRANS_SETTINGS CCB failed"); 325874840Sken if (arglist & CAM_ARG_VERBOSE) 325974840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 326074840Sken CAM_EPF_ALL, stderr); 326146581Sken retval = 1; 326246581Sken goto get_print_cts_bailout; 326346581Sken } 326446581Sken 326546581Sken if (quiet == 0) 326646581Sken cts_print(device, &ccb->cts); 326746581Sken 326846581Sken if (cts != NULL) 326946581Sken bcopy(&ccb->cts, cts, sizeof(struct ccb_trans_settings)); 327046581Sken 327146581Skenget_print_cts_bailout: 327246581Sken 327346581Sken cam_freeccb(ccb); 327446581Sken 327546581Sken return(retval); 327646581Sken} 327746581Sken 327846581Skenstatic int 327946581Skenratecontrol(struct cam_device *device, int retry_count, int timeout, 328046581Sken int argc, char **argv, char *combinedopt) 328146581Sken{ 328246581Sken int c; 328346581Sken union ccb *ccb; 328446581Sken int user_settings = 0; 328546581Sken int retval = 0; 328646581Sken int disc_enable = -1, tag_enable = -1; 3287199821Smav int mode = -1; 328846581Sken int offset = -1; 328946581Sken double syncrate = -1; 329046581Sken int bus_width = -1; 329146581Sken int quiet = 0; 329246581Sken int change_settings = 0, send_tur = 0; 329346581Sken struct ccb_pathinq cpi; 329446581Sken 329546581Sken ccb = cam_getccb(device); 329646581Sken if (ccb == NULL) { 329746581Sken warnx("ratecontrol: error allocating ccb"); 329846581Sken return(1); 329946581Sken } 330046581Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 330146581Sken switch(c){ 330246581Sken case 'a': 330346581Sken send_tur = 1; 330446581Sken break; 330546581Sken case 'c': 330646581Sken user_settings = 0; 330746581Sken break; 330846581Sken case 'D': 330946581Sken if (strncasecmp(optarg, "enable", 6) == 0) 331046581Sken disc_enable = 1; 331146581Sken else if (strncasecmp(optarg, "disable", 7) == 0) 331246581Sken disc_enable = 0; 331346581Sken else { 331446581Sken warnx("-D argument \"%s\" is unknown", optarg); 331546581Sken retval = 1; 331646581Sken goto ratecontrol_bailout; 331746581Sken } 331846581Sken change_settings = 1; 331946581Sken break; 3320199821Smav case 'M': 3321199821Smav mode = ata_string2mode(optarg); 3322199821Smav if (mode < 0) { 3323199821Smav warnx("unknown mode '%s'", optarg); 3324199821Smav retval = 1; 3325199821Smav goto ratecontrol_bailout; 3326199821Smav } 3327199821Smav change_settings = 1; 3328199821Smav break; 332946581Sken case 'O': 333046581Sken offset = strtol(optarg, NULL, 0); 333146581Sken if (offset < 0) { 333246581Sken warnx("offset value %d is < 0", offset); 333346581Sken retval = 1; 333446581Sken goto ratecontrol_bailout; 333546581Sken } 333646581Sken change_settings = 1; 333746581Sken break; 333846581Sken case 'q': 333946581Sken quiet++; 334046581Sken break; 334146581Sken case 'R': 334246581Sken syncrate = atof(optarg); 334346581Sken if (syncrate < 0) { 334446581Sken warnx("sync rate %f is < 0", syncrate); 334546581Sken retval = 1; 334646581Sken goto ratecontrol_bailout; 334746581Sken } 334846581Sken change_settings = 1; 334946581Sken break; 335046581Sken case 'T': 335146581Sken if (strncasecmp(optarg, "enable", 6) == 0) 335246581Sken tag_enable = 1; 335346581Sken else if (strncasecmp(optarg, "disable", 7) == 0) 335446581Sken tag_enable = 0; 335546581Sken else { 335646581Sken warnx("-T argument \"%s\" is unknown", optarg); 335746581Sken retval = 1; 335846581Sken goto ratecontrol_bailout; 335946581Sken } 336046581Sken change_settings = 1; 336146581Sken break; 336246581Sken case 'U': 336346581Sken user_settings = 1; 336446581Sken break; 336546581Sken case 'W': 336646581Sken bus_width = strtol(optarg, NULL, 0); 336746581Sken if (bus_width < 0) { 336846581Sken warnx("bus width %d is < 0", bus_width); 336946581Sken retval = 1; 337046581Sken goto ratecontrol_bailout; 337146581Sken } 337246581Sken change_settings = 1; 337346581Sken break; 337446581Sken default: 337546581Sken break; 337646581Sken } 337746581Sken } 337846581Sken bzero(&(&ccb->ccb_h)[1], 337946581Sken sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr)); 338046581Sken /* 338146581Sken * Grab path inquiry information, so we can determine whether 338246581Sken * or not the initiator is capable of the things that the user 338346581Sken * requests. 338446581Sken */ 338546581Sken ccb->ccb_h.func_code = XPT_PATH_INQ; 338646581Sken if (cam_send_ccb(device, ccb) < 0) { 338746581Sken perror("error sending XPT_PATH_INQ CCB"); 338874840Sken if (arglist & CAM_ARG_VERBOSE) { 338974840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 339074840Sken CAM_EPF_ALL, stderr); 339174840Sken } 339246581Sken retval = 1; 339346581Sken goto ratecontrol_bailout; 339446581Sken } 339546581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 339674840Sken warnx("XPT_PATH_INQ CCB failed"); 339774840Sken if (arglist & CAM_ARG_VERBOSE) { 339874840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 339974840Sken CAM_EPF_ALL, stderr); 340074840Sken } 340146581Sken retval = 1; 340246581Sken goto ratecontrol_bailout; 340346581Sken } 340446581Sken bcopy(&ccb->cpi, &cpi, sizeof(struct ccb_pathinq)); 340546581Sken bzero(&(&ccb->ccb_h)[1], 340646581Sken sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr)); 3407199821Smav if (quiet == 0) { 3408199821Smav fprintf(stdout, "%s parameters:\n", 3409199821Smav user_settings ? "User" : "Current"); 3410199821Smav } 341146581Sken retval = get_print_cts(device, user_settings, quiet, &ccb->cts); 341246581Sken if (retval != 0) 341346581Sken goto ratecontrol_bailout; 341446581Sken 341546581Sken if (arglist & CAM_ARG_VERBOSE) 341646581Sken cpi_print(&cpi); 341746581Sken 341846581Sken if (change_settings) { 3419163896Smjacob int didsettings = 0; 3420163896Smjacob struct ccb_trans_settings_spi *spi = NULL; 3421236437Smav struct ccb_trans_settings_pata *pata = NULL; 3422236437Smav struct ccb_trans_settings_sata *sata = NULL; 3423199821Smav struct ccb_trans_settings_ata *ata = NULL; 3424163896Smjacob struct ccb_trans_settings_scsi *scsi = NULL; 3425163896Smjacob 3426199821Smav if (ccb->cts.transport == XPORT_SPI) 3427163896Smjacob spi = &ccb->cts.xport_specific.spi; 3428199821Smav if (ccb->cts.transport == XPORT_ATA) 3429236437Smav pata = &ccb->cts.xport_specific.ata; 3430199821Smav if (ccb->cts.transport == XPORT_SATA) 3431199821Smav sata = &ccb->cts.xport_specific.sata; 3432236437Smav if (ccb->cts.protocol == PROTO_ATA) 3433236437Smav ata = &ccb->cts.proto_specific.ata; 3434199821Smav if (ccb->cts.protocol == PROTO_SCSI) 3435163896Smjacob scsi = &ccb->cts.proto_specific.scsi; 3436199821Smav ccb->cts.xport_specific.valid = 0; 3437199821Smav ccb->cts.proto_specific.valid = 0; 3438163896Smjacob if (spi && disc_enable != -1) { 3439163896Smjacob spi->valid |= CTS_SPI_VALID_DISC; 344046581Sken if (disc_enable == 0) 3441163896Smjacob spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 344246581Sken else 3443163896Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 3444236285Seadler didsettings++; 3445163896Smjacob } 3446236437Smav if (tag_enable != -1) { 344746581Sken if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0) { 344846581Sken warnx("HBA does not support tagged queueing, " 344946581Sken "so you cannot modify tag settings"); 345046581Sken retval = 1; 345146581Sken goto ratecontrol_bailout; 345246581Sken } 3453236437Smav if (ata) { 3454236437Smav ata->valid |= CTS_SCSI_VALID_TQ; 3455236437Smav if (tag_enable == 0) 3456236437Smav ata->flags &= ~CTS_ATA_FLAGS_TAG_ENB; 3457236437Smav else 3458236437Smav ata->flags |= CTS_ATA_FLAGS_TAG_ENB; 3459236437Smav didsettings++; 3460236437Smav } else if (scsi) { 3461236437Smav scsi->valid |= CTS_SCSI_VALID_TQ; 3462236437Smav if (tag_enable == 0) 3463236437Smav scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 3464236437Smav else 3465236437Smav scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 3466236437Smav didsettings++; 3467236437Smav } 3468163896Smjacob } 3469163896Smjacob if (spi && offset != -1) { 347046581Sken if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) { 3471199821Smav warnx("HBA is not capable of changing offset"); 347246581Sken retval = 1; 347346581Sken goto ratecontrol_bailout; 347446581Sken } 3475163896Smjacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 3476163896Smjacob spi->sync_offset = offset; 3477163896Smjacob didsettings++; 3478163896Smjacob } 3479163896Smjacob if (spi && syncrate != -1) { 348046581Sken int prelim_sync_period; 348146581Sken 348246581Sken if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) { 3483199821Smav warnx("HBA is not capable of changing " 3484199821Smav "transfer rates"); 348546581Sken retval = 1; 348646581Sken goto ratecontrol_bailout; 348746581Sken } 3488163896Smjacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 348946581Sken /* 349046581Sken * The sync rate the user gives us is in MHz. 349146581Sken * We need to translate it into KHz for this 349246581Sken * calculation. 349346581Sken */ 349446581Sken syncrate *= 1000; 349546581Sken /* 349646581Sken * Next, we calculate a "preliminary" sync period 349746581Sken * in tenths of a nanosecond. 349846581Sken */ 349946581Sken if (syncrate == 0) 350046581Sken prelim_sync_period = 0; 350146581Sken else 350246581Sken prelim_sync_period = 10000000 / syncrate; 3503163896Smjacob spi->sync_period = 350446581Sken scsi_calc_syncparam(prelim_sync_period); 3505163896Smjacob didsettings++; 3506163896Smjacob } 3507199821Smav if (sata && syncrate != -1) { 3508199821Smav if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) { 3509199821Smav warnx("HBA is not capable of changing " 3510199821Smav "transfer rates"); 3511199821Smav retval = 1; 3512199821Smav goto ratecontrol_bailout; 3513199821Smav } 3514236437Smav if (!user_settings) { 3515236437Smav warnx("You can modify only user rate " 3516236437Smav "settings for SATA"); 3517236437Smav retval = 1; 3518236437Smav goto ratecontrol_bailout; 3519236437Smav } 3520199821Smav sata->revision = ata_speed2revision(syncrate * 100); 3521199821Smav if (sata->revision < 0) { 3522199821Smav warnx("Invalid rate %f", syncrate); 3523199821Smav retval = 1; 3524199821Smav goto ratecontrol_bailout; 3525199821Smav } 3526199821Smav sata->valid |= CTS_SATA_VALID_REVISION; 3527199821Smav didsettings++; 3528199821Smav } 3529236437Smav if ((pata || sata) && mode != -1) { 3530199821Smav if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) { 3531199821Smav warnx("HBA is not capable of changing " 3532199821Smav "transfer rates"); 3533199821Smav retval = 1; 3534199821Smav goto ratecontrol_bailout; 3535199821Smav } 3536236437Smav if (!user_settings) { 3537236437Smav warnx("You can modify only user mode " 3538236437Smav "settings for ATA/SATA"); 3539236437Smav retval = 1; 3540236437Smav goto ratecontrol_bailout; 3541236437Smav } 3542236437Smav if (pata) { 3543236437Smav pata->mode = mode; 3544236437Smav pata->valid |= CTS_ATA_VALID_MODE; 3545199821Smav } else { 3546199821Smav sata->mode = mode; 3547199821Smav sata->valid |= CTS_SATA_VALID_MODE; 3548199821Smav } 3549199821Smav didsettings++; 3550199821Smav } 355146581Sken /* 355246581Sken * The bus_width argument goes like this: 355346581Sken * 0 == 8 bit 355446581Sken * 1 == 16 bit 355546581Sken * 2 == 32 bit 355646581Sken * Therefore, if you shift the number of bits given on the 355746581Sken * command line right by 4, you should get the correct 355846581Sken * number. 355946581Sken */ 3560163896Smjacob if (spi && bus_width != -1) { 356146581Sken /* 356246581Sken * We might as well validate things here with a 356346581Sken * decipherable error message, rather than what 356446581Sken * will probably be an indecipherable error message 356546581Sken * by the time it gets back to us. 356646581Sken */ 356746581Sken if ((bus_width == 16) 356846581Sken && ((cpi.hba_inquiry & PI_WIDE_16) == 0)) { 356946581Sken warnx("HBA does not support 16 bit bus width"); 357046581Sken retval = 1; 357146581Sken goto ratecontrol_bailout; 357246581Sken } else if ((bus_width == 32) 357346581Sken && ((cpi.hba_inquiry & PI_WIDE_32) == 0)) { 357446581Sken warnx("HBA does not support 32 bit bus width"); 357546581Sken retval = 1; 357646581Sken goto ratecontrol_bailout; 357751723Sken } else if ((bus_width != 8) 357851723Sken && (bus_width != 16) 357951723Sken && (bus_width != 32)) { 358046581Sken warnx("Invalid bus width %d", bus_width); 358146581Sken retval = 1; 358246581Sken goto ratecontrol_bailout; 358346581Sken } 3584163896Smjacob spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 3585163896Smjacob spi->bus_width = bus_width >> 4; 3586163896Smjacob didsettings++; 3587163896Smjacob } 3588163896Smjacob if (didsettings == 0) { 3589163896Smjacob goto ratecontrol_bailout; 3590163896Smjacob } 359146581Sken ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 359246581Sken if (cam_send_ccb(device, ccb) < 0) { 359346581Sken perror("error sending XPT_SET_TRAN_SETTINGS CCB"); 359474840Sken if (arglist & CAM_ARG_VERBOSE) { 359574840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 359674840Sken CAM_EPF_ALL, stderr); 359774840Sken } 359846581Sken retval = 1; 359946581Sken goto ratecontrol_bailout; 360046581Sken } 360146581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 360274840Sken warnx("XPT_SET_TRANS_SETTINGS CCB failed"); 360374840Sken if (arglist & CAM_ARG_VERBOSE) { 360474840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 360574840Sken CAM_EPF_ALL, stderr); 360674840Sken } 360746581Sken retval = 1; 360846581Sken goto ratecontrol_bailout; 360946581Sken } 361046581Sken } 361146581Sken if (send_tur) { 361246581Sken retval = testunitready(device, retry_count, timeout, 361346581Sken (arglist & CAM_ARG_VERBOSE) ? 0 : 1); 361446581Sken /* 361546581Sken * If the TUR didn't succeed, just bail. 361646581Sken */ 361746581Sken if (retval != 0) { 361846581Sken if (quiet == 0) 361946581Sken fprintf(stderr, "Test Unit Ready failed\n"); 362046581Sken goto ratecontrol_bailout; 362146581Sken } 3622236437Smav } 3623236437Smav if ((change_settings || send_tur) && !quiet && 3624236437Smav (ccb->cts.transport == XPORT_ATA || 3625236437Smav ccb->cts.transport == XPORT_SATA || send_tur)) { 3626199821Smav fprintf(stdout, "New parameters:\n"); 362746581Sken retval = get_print_cts(device, user_settings, 0, NULL); 362846581Sken } 362946581Sken 363046581Skenratecontrol_bailout: 363146581Sken cam_freeccb(ccb); 363246581Sken return(retval); 363346581Sken} 363446581Sken 363560767Skenstatic int 363660767Skenscsiformat(struct cam_device *device, int argc, char **argv, 363760767Sken char *combinedopt, int retry_count, int timeout) 363860767Sken{ 363960767Sken union ccb *ccb; 364060767Sken int c; 364160767Sken int ycount = 0, quiet = 0; 3642227961Semaste int error = 0, retval = 0; 364360767Sken int use_timeout = 10800 * 1000; 364460767Sken int immediate = 1; 364560767Sken struct format_defect_list_header fh; 364660767Sken u_int8_t *data_ptr = NULL; 364760767Sken u_int32_t dxfer_len = 0; 364860767Sken u_int8_t byte2 = 0; 364960767Sken int num_warnings = 0; 3650144134Sken int reportonly = 0; 365160767Sken 365260767Sken ccb = cam_getccb(device); 365360767Sken 365460767Sken if (ccb == NULL) { 365560767Sken warnx("scsiformat: error allocating ccb"); 365660767Sken return(1); 365760767Sken } 365860767Sken 365960767Sken bzero(&(&ccb->ccb_h)[1], 366060767Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 366160767Sken 366260767Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 366360767Sken switch(c) { 366460767Sken case 'q': 366560767Sken quiet++; 366660767Sken break; 3667144134Sken case 'r': 3668144134Sken reportonly = 1; 3669144134Sken break; 367060767Sken case 'w': 367160767Sken immediate = 0; 367260767Sken break; 367360767Sken case 'y': 367460767Sken ycount++; 367560767Sken break; 367660767Sken } 367760767Sken } 367860767Sken 3679144134Sken if (reportonly) 3680144134Sken goto doreport; 3681144134Sken 368260767Sken if (quiet == 0) { 368360767Sken fprintf(stdout, "You are about to REMOVE ALL DATA from the " 368460767Sken "following device:\n"); 368560767Sken 368660767Sken error = scsidoinquiry(device, argc, argv, combinedopt, 368760767Sken retry_count, timeout); 368860767Sken 368960767Sken if (error != 0) { 369060767Sken warnx("scsiformat: error sending inquiry"); 369160767Sken goto scsiformat_bailout; 369260767Sken } 369360767Sken } 369460767Sken 369560767Sken if (ycount == 0) { 3696227961Semaste if (!get_confirmation()) { 369760767Sken error = 1; 369860767Sken goto scsiformat_bailout; 369960767Sken } 370060767Sken } 370160767Sken 370260767Sken if (timeout != 0) 370360767Sken use_timeout = timeout; 370460767Sken 370560767Sken if (quiet == 0) { 370660767Sken fprintf(stdout, "Current format timeout is %d seconds\n", 370760767Sken use_timeout / 1000); 370860767Sken } 370960767Sken 371060767Sken /* 371160767Sken * If the user hasn't disabled questions and didn't specify a 371260767Sken * timeout on the command line, ask them if they want the current 371360767Sken * timeout. 371460767Sken */ 371560767Sken if ((ycount == 0) 371660767Sken && (timeout == 0)) { 371760767Sken char str[1024]; 371860767Sken int new_timeout = 0; 371960767Sken 372060767Sken fprintf(stdout, "Enter new timeout in seconds or press\n" 372160767Sken "return to keep the current timeout [%d] ", 372260767Sken use_timeout / 1000); 372360767Sken 372460767Sken if (fgets(str, sizeof(str), stdin) != NULL) { 372560767Sken if (str[0] != '\0') 372660767Sken new_timeout = atoi(str); 372760767Sken } 372860767Sken 372960767Sken if (new_timeout != 0) { 373060767Sken use_timeout = new_timeout * 1000; 373160767Sken fprintf(stdout, "Using new timeout value %d\n", 373260767Sken use_timeout / 1000); 373360767Sken } 373460767Sken } 373560767Sken 373660767Sken /* 373760767Sken * Keep this outside the if block below to silence any unused 373860767Sken * variable warnings. 373960767Sken */ 374060767Sken bzero(&fh, sizeof(fh)); 374160767Sken 374260767Sken /* 374360767Sken * If we're in immediate mode, we've got to include the format 374460767Sken * header 374560767Sken */ 374660767Sken if (immediate != 0) { 374760767Sken fh.byte2 = FU_DLH_IMMED; 374860767Sken data_ptr = (u_int8_t *)&fh; 374960767Sken dxfer_len = sizeof(fh); 375060767Sken byte2 = FU_FMT_DATA; 375160767Sken } else if (quiet == 0) { 375260767Sken fprintf(stdout, "Formatting..."); 375360767Sken fflush(stdout); 375460767Sken } 375560767Sken 375660767Sken scsi_format_unit(&ccb->csio, 375760767Sken /* retries */ retry_count, 375860767Sken /* cbfcnp */ NULL, 375960767Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 376060767Sken /* byte2 */ byte2, 376160767Sken /* ileave */ 0, 376260767Sken /* data_ptr */ data_ptr, 376360767Sken /* dxfer_len */ dxfer_len, 376460767Sken /* sense_len */ SSD_FULL_SIZE, 376560767Sken /* timeout */ use_timeout); 376660767Sken 376760767Sken /* Disable freezing the device queue */ 376860767Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 376960767Sken 377060767Sken if (arglist & CAM_ARG_ERR_RECOVER) 377160767Sken ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 377260767Sken 377360767Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 377460767Sken || ((immediate == 0) 377560767Sken && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP))) { 377669254Skris const char errstr[] = "error sending format command"; 377760767Sken 377860767Sken if (retval < 0) 377960767Sken warn(errstr); 378060767Sken else 378160767Sken warnx(errstr); 378260767Sken 378360767Sken if (arglist & CAM_ARG_VERBOSE) { 378474840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 378574840Sken CAM_EPF_ALL, stderr); 378660767Sken } 378760767Sken error = 1; 378860767Sken goto scsiformat_bailout; 378960767Sken } 379060767Sken 379160767Sken /* 379260767Sken * If we ran in non-immediate mode, we already checked for errors 379360767Sken * above and printed out any necessary information. If we're in 379460767Sken * immediate mode, we need to loop through and get status 379560767Sken * information periodically. 379660767Sken */ 379760767Sken if (immediate == 0) { 379860767Sken if (quiet == 0) { 379960767Sken fprintf(stdout, "Format Complete\n"); 380060767Sken } 380160767Sken goto scsiformat_bailout; 380260767Sken } 380360767Sken 3804144134Skendoreport: 380560767Sken do { 380660767Sken cam_status status; 380760767Sken 380860767Sken bzero(&(&ccb->ccb_h)[1], 380960767Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 381060767Sken 381160767Sken /* 381260767Sken * There's really no need to do error recovery or 381360767Sken * retries here, since we're just going to sit in a 381460767Sken * loop and wait for the device to finish formatting. 381560767Sken */ 381660767Sken scsi_test_unit_ready(&ccb->csio, 381760767Sken /* retries */ 0, 381860767Sken /* cbfcnp */ NULL, 381960767Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 382060767Sken /* sense_len */ SSD_FULL_SIZE, 382160767Sken /* timeout */ 5000); 382260767Sken 382360767Sken /* Disable freezing the device queue */ 382460767Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 382560767Sken 382660767Sken retval = cam_send_ccb(device, ccb); 382760767Sken 382860767Sken /* 382960767Sken * If we get an error from the ioctl, bail out. SCSI 383060767Sken * errors are expected. 383160767Sken */ 383260767Sken if (retval < 0) { 383360767Sken warn("error sending CAMIOCOMMAND ioctl"); 383460767Sken if (arglist & CAM_ARG_VERBOSE) { 383574840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 383674840Sken CAM_EPF_ALL, stderr); 383760767Sken } 383860767Sken error = 1; 383960767Sken goto scsiformat_bailout; 384060767Sken } 384160767Sken 384260767Sken status = ccb->ccb_h.status & CAM_STATUS_MASK; 384360767Sken 384460767Sken if ((status != CAM_REQ_CMP) 384574840Sken && (status == CAM_SCSI_STATUS_ERROR) 3846144134Sken && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) { 384760767Sken struct scsi_sense_data *sense; 384860767Sken int error_code, sense_key, asc, ascq; 384960767Sken 385060767Sken sense = &ccb->csio.sense_data; 3851225950Sken scsi_extract_sense_len(sense, ccb->csio.sense_len - 3852225950Sken ccb->csio.sense_resid, &error_code, &sense_key, 3853225950Sken &asc, &ascq, /*show_errors*/ 1); 385460767Sken 385560767Sken /* 385660767Sken * According to the SCSI-2 and SCSI-3 specs, a 385760767Sken * drive that is in the middle of a format should 385860767Sken * return NOT READY with an ASC of "logical unit 385960767Sken * not ready, format in progress". The sense key 386060767Sken * specific bytes will then be a progress indicator. 386160767Sken */ 386260767Sken if ((sense_key == SSD_KEY_NOT_READY) 386360767Sken && (asc == 0x04) && (ascq == 0x04)) { 3864225950Sken uint8_t sks[3]; 3865225950Sken 3866225950Sken if ((scsi_get_sks(sense, ccb->csio.sense_len - 3867225950Sken ccb->csio.sense_resid, sks) == 0) 386860767Sken && (quiet == 0)) { 386960767Sken int val; 387060767Sken u_int64_t percentage; 387160767Sken 3872225950Sken val = scsi_2btoul(&sks[1]); 387360767Sken percentage = 10000 * val; 387460767Sken 387560767Sken fprintf(stdout, 3876111195Sjohan "\rFormatting: %ju.%02u %% " 387760767Sken "(%d/%d) done", 3878214321Smav (uintmax_t)(percentage / 3879111195Sjohan (0x10000 * 100)), 3880214321Smav (unsigned)((percentage / 3881111195Sjohan 0x10000) % 100), 388260767Sken val, 0x10000); 388360767Sken fflush(stdout); 388460767Sken } else if ((quiet == 0) 388560767Sken && (++num_warnings <= 1)) { 388660767Sken warnx("Unexpected SCSI Sense Key " 388760767Sken "Specific value returned " 388860767Sken "during format:"); 388960767Sken scsi_sense_print(device, &ccb->csio, 389060767Sken stderr); 389160767Sken warnx("Unable to print status " 389260767Sken "information, but format will " 389360767Sken "proceed."); 389460767Sken warnx("will exit when format is " 389560767Sken "complete"); 389660767Sken } 389760767Sken sleep(1); 389860767Sken } else { 389960767Sken warnx("Unexpected SCSI error during format"); 390074840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 390174840Sken CAM_EPF_ALL, stderr); 390260767Sken error = 1; 390360767Sken goto scsiformat_bailout; 390460767Sken } 390560767Sken 390660767Sken } else if (status != CAM_REQ_CMP) { 390760767Sken warnx("Unexpected CAM status %#x", status); 390874840Sken if (arglist & CAM_ARG_VERBOSE) 390974840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 391074840Sken CAM_EPF_ALL, stderr); 391160767Sken error = 1; 391260767Sken goto scsiformat_bailout; 391360767Sken } 391460767Sken 391560767Sken } while((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP); 391660767Sken 391760767Sken if (quiet == 0) 391860767Sken fprintf(stdout, "\nFormat Complete\n"); 391960767Sken 392060767Skenscsiformat_bailout: 392160767Sken 392260767Sken cam_freeccb(ccb); 392360767Sken 392460767Sken return(error); 392560767Sken} 3926161506Sken 3927161506Skenstatic int 3928161506Skenscsireportluns(struct cam_device *device, int argc, char **argv, 3929161506Sken char *combinedopt, int retry_count, int timeout) 3930161506Sken{ 3931161506Sken union ccb *ccb; 3932161506Sken int c, countonly, lunsonly; 3933161506Sken struct scsi_report_luns_data *lundata; 3934161506Sken int alloc_len; 3935161506Sken uint8_t report_type; 3936161506Sken uint32_t list_len, i, j; 3937161506Sken int retval; 3938161506Sken 3939161506Sken retval = 0; 3940161506Sken lundata = NULL; 3941161506Sken report_type = RPL_REPORT_DEFAULT; 3942161506Sken ccb = cam_getccb(device); 3943161506Sken 3944161506Sken if (ccb == NULL) { 3945161506Sken warnx("%s: error allocating ccb", __func__); 3946161506Sken return (1); 3947161506Sken } 3948161506Sken 3949161506Sken bzero(&(&ccb->ccb_h)[1], 3950161506Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 3951161506Sken 3952161506Sken countonly = 0; 3953161506Sken lunsonly = 0; 3954161506Sken 3955161506Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 3956161506Sken switch (c) { 3957161506Sken case 'c': 3958161506Sken countonly++; 3959161506Sken break; 3960161506Sken case 'l': 3961161506Sken lunsonly++; 3962161506Sken break; 3963161506Sken case 'r': 3964161506Sken if (strcasecmp(optarg, "default") == 0) 3965161506Sken report_type = RPL_REPORT_DEFAULT; 3966161506Sken else if (strcasecmp(optarg, "wellknown") == 0) 3967161506Sken report_type = RPL_REPORT_WELLKNOWN; 3968161506Sken else if (strcasecmp(optarg, "all") == 0) 3969161506Sken report_type = RPL_REPORT_ALL; 3970161506Sken else { 3971161506Sken warnx("%s: invalid report type \"%s\"", 3972161506Sken __func__, optarg); 3973161506Sken retval = 1; 3974161506Sken goto bailout; 3975161506Sken } 3976161506Sken break; 3977161506Sken default: 3978161506Sken break; 3979161506Sken } 3980161506Sken } 3981161506Sken 3982161506Sken if ((countonly != 0) 3983161506Sken && (lunsonly != 0)) { 3984161506Sken warnx("%s: you can only specify one of -c or -l", __func__); 3985161506Sken retval = 1; 3986161506Sken goto bailout; 3987161506Sken } 3988161506Sken /* 3989161506Sken * According to SPC-4, the allocation length must be at least 16 3990161506Sken * bytes -- enough for the header and one LUN. 3991161506Sken */ 3992161506Sken alloc_len = sizeof(*lundata) + 8; 3993161506Sken 3994161506Skenretry: 3995161506Sken 3996161506Sken lundata = malloc(alloc_len); 3997161506Sken 3998161506Sken if (lundata == NULL) { 3999161506Sken warn("%s: error mallocing %d bytes", __func__, alloc_len); 4000161506Sken retval = 1; 4001161506Sken goto bailout; 4002161506Sken } 4003161506Sken 4004161506Sken scsi_report_luns(&ccb->csio, 4005161506Sken /*retries*/ retry_count, 4006161506Sken /*cbfcnp*/ NULL, 4007161506Sken /*tag_action*/ MSG_SIMPLE_Q_TAG, 4008161506Sken /*select_report*/ report_type, 4009161506Sken /*rpl_buf*/ lundata, 4010161506Sken /*alloc_len*/ alloc_len, 4011161506Sken /*sense_len*/ SSD_FULL_SIZE, 4012161506Sken /*timeout*/ timeout ? timeout : 5000); 4013161506Sken 4014161506Sken /* Disable freezing the device queue */ 4015161506Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 4016161506Sken 4017161506Sken if (arglist & CAM_ARG_ERR_RECOVER) 4018161506Sken ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 4019161506Sken 4020161506Sken if (cam_send_ccb(device, ccb) < 0) { 4021161506Sken warn("error sending REPORT LUNS command"); 4022161506Sken 4023161506Sken if (arglist & CAM_ARG_VERBOSE) 4024161506Sken cam_error_print(device, ccb, CAM_ESF_ALL, 4025161506Sken CAM_EPF_ALL, stderr); 4026161506Sken 4027161506Sken retval = 1; 4028161506Sken goto bailout; 4029161506Sken } 4030161506Sken 4031161506Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 4032161506Sken cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); 4033161506Sken retval = 1; 4034161506Sken goto bailout; 4035161506Sken } 4036161506Sken 4037161506Sken 4038161506Sken list_len = scsi_4btoul(lundata->length); 4039161506Sken 4040161506Sken /* 4041161506Sken * If we need to list the LUNs, and our allocation 4042161506Sken * length was too short, reallocate and retry. 4043161506Sken */ 4044161506Sken if ((countonly == 0) 4045161506Sken && (list_len > (alloc_len - sizeof(*lundata)))) { 4046161506Sken alloc_len = list_len + sizeof(*lundata); 4047161506Sken free(lundata); 4048161506Sken goto retry; 4049161506Sken } 4050161506Sken 4051161506Sken if (lunsonly == 0) 4052161506Sken fprintf(stdout, "%u LUN%s found\n", list_len / 8, 4053161506Sken ((list_len / 8) > 1) ? "s" : ""); 4054161506Sken 4055161506Sken if (countonly != 0) 4056161506Sken goto bailout; 4057161506Sken 4058161506Sken for (i = 0; i < (list_len / 8); i++) { 4059161506Sken int no_more; 4060161506Sken 4061161506Sken no_more = 0; 4062161506Sken for (j = 0; j < sizeof(lundata->luns[i].lundata); j += 2) { 4063161506Sken if (j != 0) 4064161506Sken fprintf(stdout, ","); 4065161506Sken switch (lundata->luns[i].lundata[j] & 4066161506Sken RPL_LUNDATA_ATYP_MASK) { 4067161506Sken case RPL_LUNDATA_ATYP_PERIPH: 4068161506Sken if ((lundata->luns[i].lundata[j] & 4069161506Sken RPL_LUNDATA_PERIPH_BUS_MASK) != 0) 4070214321Smav fprintf(stdout, "%d:", 4071161506Sken lundata->luns[i].lundata[j] & 4072161506Sken RPL_LUNDATA_PERIPH_BUS_MASK); 4073161506Sken else if ((j == 0) 4074161506Sken && ((lundata->luns[i].lundata[j+2] & 4075161506Sken RPL_LUNDATA_PERIPH_BUS_MASK) == 0)) 4076161506Sken no_more = 1; 4077161506Sken 4078161506Sken fprintf(stdout, "%d", 4079161506Sken lundata->luns[i].lundata[j+1]); 4080161506Sken break; 4081161506Sken case RPL_LUNDATA_ATYP_FLAT: { 4082161506Sken uint8_t tmplun[2]; 4083161506Sken tmplun[0] = lundata->luns[i].lundata[j] & 4084161506Sken RPL_LUNDATA_FLAT_LUN_MASK; 4085161506Sken tmplun[1] = lundata->luns[i].lundata[j+1]; 4086161506Sken 4087161506Sken fprintf(stdout, "%d", scsi_2btoul(tmplun)); 4088161506Sken no_more = 1; 4089161506Sken break; 4090161506Sken } 4091161506Sken case RPL_LUNDATA_ATYP_LUN: 4092161506Sken fprintf(stdout, "%d:%d:%d", 4093161506Sken (lundata->luns[i].lundata[j+1] & 4094161506Sken RPL_LUNDATA_LUN_BUS_MASK) >> 5, 4095161506Sken lundata->luns[i].lundata[j] & 4096161506Sken RPL_LUNDATA_LUN_TARG_MASK, 4097161506Sken lundata->luns[i].lundata[j+1] & 4098161506Sken RPL_LUNDATA_LUN_LUN_MASK); 4099161506Sken break; 4100161506Sken case RPL_LUNDATA_ATYP_EXTLUN: { 4101229919Seadler int field_len_code, eam_code; 4102161506Sken 4103161506Sken eam_code = lundata->luns[i].lundata[j] & 4104161506Sken RPL_LUNDATA_EXT_EAM_MASK; 4105161506Sken field_len_code = (lundata->luns[i].lundata[j] & 4106161506Sken RPL_LUNDATA_EXT_LEN_MASK) >> 4; 4107214321Smav 4108161506Sken if ((eam_code == RPL_LUNDATA_EXT_EAM_WK) 4109161506Sken && (field_len_code == 0x00)) { 4110161506Sken fprintf(stdout, "%d", 4111161506Sken lundata->luns[i].lundata[j+1]); 4112161506Sken } else if ((eam_code == 4113161506Sken RPL_LUNDATA_EXT_EAM_NOT_SPEC) 4114161506Sken && (field_len_code == 0x03)) { 4115161506Sken uint8_t tmp_lun[8]; 4116161506Sken 4117161506Sken /* 4118161506Sken * This format takes up all 8 bytes. 4119161506Sken * If we aren't starting at offset 0, 4120161506Sken * that's a bug. 4121161506Sken */ 4122161506Sken if (j != 0) { 4123161506Sken fprintf(stdout, "Invalid " 4124161506Sken "offset %d for " 4125161506Sken "Extended LUN not " 4126161506Sken "specified format", j); 4127161506Sken no_more = 1; 4128161506Sken break; 4129161506Sken } 4130161506Sken bzero(tmp_lun, sizeof(tmp_lun)); 4131161506Sken bcopy(&lundata->luns[i].lundata[j+1], 4132161506Sken &tmp_lun[1], sizeof(tmp_lun) - 1); 4133161506Sken fprintf(stdout, "%#jx", 4134161506Sken (intmax_t)scsi_8btou64(tmp_lun)); 4135161506Sken no_more = 1; 4136161506Sken } else { 4137161506Sken fprintf(stderr, "Unknown Extended LUN" 4138161506Sken "Address method %#x, length " 4139161506Sken "code %#x", eam_code, 4140161506Sken field_len_code); 4141161506Sken no_more = 1; 4142161506Sken } 4143161506Sken break; 4144161506Sken } 4145161506Sken default: 4146161506Sken fprintf(stderr, "Unknown LUN address method " 4147161506Sken "%#x\n", lundata->luns[i].lundata[0] & 4148161506Sken RPL_LUNDATA_ATYP_MASK); 4149161506Sken break; 4150161506Sken } 4151161506Sken /* 4152161506Sken * For the flat addressing method, there are no 4153161506Sken * other levels after it. 4154161506Sken */ 4155161506Sken if (no_more != 0) 4156161506Sken break; 4157161506Sken } 4158161506Sken fprintf(stdout, "\n"); 4159161506Sken } 4160161506Sken 4161161506Skenbailout: 4162161506Sken 4163161506Sken cam_freeccb(ccb); 4164161506Sken 4165161506Sken free(lundata); 4166161506Sken 4167161506Sken return (retval); 4168161506Sken} 4169161506Sken 4170172093Skenstatic int 4171172093Skenscsireadcapacity(struct cam_device *device, int argc, char **argv, 4172172093Sken char *combinedopt, int retry_count, int timeout) 4173172093Sken{ 4174172093Sken union ccb *ccb; 4175172093Sken int blocksizeonly, humanize, numblocks, quiet, sizeonly, baseten; 4176172093Sken struct scsi_read_capacity_data rcap; 4177172093Sken struct scsi_read_capacity_data_long rcaplong; 4178172093Sken uint64_t maxsector; 4179172093Sken uint32_t block_len; 4180172093Sken int retval; 4181172093Sken int c; 4182172093Sken 4183172093Sken blocksizeonly = 0; 4184172093Sken humanize = 0; 4185172093Sken numblocks = 0; 4186172093Sken quiet = 0; 4187172093Sken sizeonly = 0; 4188172093Sken baseten = 0; 4189172093Sken retval = 0; 4190172093Sken 4191172093Sken ccb = cam_getccb(device); 4192172093Sken 4193172093Sken if (ccb == NULL) { 4194172093Sken warnx("%s: error allocating ccb", __func__); 4195172093Sken return (1); 4196172093Sken } 4197172093Sken 4198172093Sken bzero(&(&ccb->ccb_h)[1], 4199172093Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 4200172093Sken 4201172093Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 4202172093Sken switch (c) { 4203172093Sken case 'b': 4204172093Sken blocksizeonly++; 4205172093Sken break; 4206172093Sken case 'h': 4207172093Sken humanize++; 4208172093Sken baseten = 0; 4209172093Sken break; 4210172093Sken case 'H': 4211172093Sken humanize++; 4212172093Sken baseten++; 4213172093Sken break; 4214172093Sken case 'N': 4215172093Sken numblocks++; 4216172093Sken break; 4217172093Sken case 'q': 4218172093Sken quiet++; 4219172093Sken break; 4220172093Sken case 's': 4221172093Sken sizeonly++; 4222172093Sken break; 4223172093Sken default: 4224172093Sken break; 4225172093Sken } 4226172093Sken } 4227172093Sken 4228172093Sken if ((blocksizeonly != 0) 4229172093Sken && (numblocks != 0)) { 4230172093Sken warnx("%s: you can only specify one of -b or -N", __func__); 4231172093Sken retval = 1; 4232172093Sken goto bailout; 4233172093Sken } 4234172093Sken 4235172093Sken if ((blocksizeonly != 0) 4236172093Sken && (sizeonly != 0)) { 4237172093Sken warnx("%s: you can only specify one of -b or -s", __func__); 4238172093Sken retval = 1; 4239172093Sken goto bailout; 4240172093Sken } 4241172093Sken 4242172093Sken if ((humanize != 0) 4243172093Sken && (quiet != 0)) { 4244172093Sken warnx("%s: you can only specify one of -h/-H or -q", __func__); 4245172093Sken retval = 1; 4246172093Sken goto bailout; 4247172093Sken } 4248172093Sken 4249172093Sken if ((humanize != 0) 4250172093Sken && (blocksizeonly != 0)) { 4251172093Sken warnx("%s: you can only specify one of -h/-H or -b", __func__); 4252172093Sken retval = 1; 4253172093Sken goto bailout; 4254172093Sken } 4255172093Sken 4256172093Sken scsi_read_capacity(&ccb->csio, 4257172093Sken /*retries*/ retry_count, 4258172093Sken /*cbfcnp*/ NULL, 4259172093Sken /*tag_action*/ MSG_SIMPLE_Q_TAG, 4260172093Sken &rcap, 4261172093Sken SSD_FULL_SIZE, 4262172093Sken /*timeout*/ timeout ? timeout : 5000); 4263172093Sken 4264172093Sken /* Disable freezing the device queue */ 4265172093Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 4266172093Sken 4267172093Sken if (arglist & CAM_ARG_ERR_RECOVER) 4268172093Sken ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 4269172093Sken 4270172093Sken if (cam_send_ccb(device, ccb) < 0) { 4271172093Sken warn("error sending READ CAPACITY command"); 4272172093Sken 4273172093Sken if (arglist & CAM_ARG_VERBOSE) 4274172093Sken cam_error_print(device, ccb, CAM_ESF_ALL, 4275172093Sken CAM_EPF_ALL, stderr); 4276172093Sken 4277172093Sken retval = 1; 4278172093Sken goto bailout; 4279172093Sken } 4280172093Sken 4281172093Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 4282172093Sken cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); 4283172093Sken retval = 1; 4284172093Sken goto bailout; 4285172093Sken } 4286172093Sken 4287172093Sken maxsector = scsi_4btoul(rcap.addr); 4288172093Sken block_len = scsi_4btoul(rcap.length); 4289172093Sken 4290172093Sken /* 4291172093Sken * A last block of 2^32-1 means that the true capacity is over 2TB, 4292172093Sken * and we need to issue the long READ CAPACITY to get the real 4293172093Sken * capacity. Otherwise, we're all set. 4294172093Sken */ 4295172093Sken if (maxsector != 0xffffffff) 4296172093Sken goto do_print; 4297172093Sken 4298172093Sken scsi_read_capacity_16(&ccb->csio, 4299172093Sken /*retries*/ retry_count, 4300172093Sken /*cbfcnp*/ NULL, 4301172093Sken /*tag_action*/ MSG_SIMPLE_Q_TAG, 4302172093Sken /*lba*/ 0, 4303172093Sken /*reladdr*/ 0, 4304172093Sken /*pmi*/ 0, 4305230590Sken /*rcap_buf*/ (uint8_t *)&rcaplong, 4306230590Sken /*rcap_buf_len*/ sizeof(rcaplong), 4307172093Sken /*sense_len*/ SSD_FULL_SIZE, 4308172093Sken /*timeout*/ timeout ? timeout : 5000); 4309172093Sken 4310172093Sken /* Disable freezing the device queue */ 4311172093Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 4312172093Sken 4313172093Sken if (arglist & CAM_ARG_ERR_RECOVER) 4314172093Sken ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 4315172093Sken 4316172093Sken if (cam_send_ccb(device, ccb) < 0) { 4317172093Sken warn("error sending READ CAPACITY (16) command"); 4318172093Sken 4319172093Sken if (arglist & CAM_ARG_VERBOSE) 4320172093Sken cam_error_print(device, ccb, CAM_ESF_ALL, 4321172093Sken CAM_EPF_ALL, stderr); 4322172093Sken 4323172093Sken retval = 1; 4324172093Sken goto bailout; 4325172093Sken } 4326172093Sken 4327172093Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 4328172093Sken cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); 4329172093Sken retval = 1; 4330172093Sken goto bailout; 4331172093Sken } 4332172093Sken 4333172093Sken maxsector = scsi_8btou64(rcaplong.addr); 4334172093Sken block_len = scsi_4btoul(rcaplong.length); 4335172093Sken 4336172093Skendo_print: 4337172093Sken if (blocksizeonly == 0) { 4338172093Sken /* 4339172093Sken * Humanize implies !quiet, and also implies numblocks. 4340172093Sken */ 4341172093Sken if (humanize != 0) { 4342172093Sken char tmpstr[6]; 4343172093Sken int64_t tmpbytes; 4344172093Sken int ret; 4345172093Sken 4346172093Sken tmpbytes = (maxsector + 1) * block_len; 4347172093Sken ret = humanize_number(tmpstr, sizeof(tmpstr), 4348172093Sken tmpbytes, "", HN_AUTOSCALE, 4349172093Sken HN_B | HN_DECIMAL | 4350172093Sken ((baseten != 0) ? 4351172093Sken HN_DIVISOR_1000 : 0)); 4352172093Sken if (ret == -1) { 4353172093Sken warnx("%s: humanize_number failed!", __func__); 4354172093Sken retval = 1; 4355172093Sken goto bailout; 4356172093Sken } 4357172093Sken fprintf(stdout, "Device Size: %s%s", tmpstr, 4358172093Sken (sizeonly == 0) ? ", " : "\n"); 4359172093Sken } else if (numblocks != 0) { 4360172093Sken fprintf(stdout, "%s%ju%s", (quiet == 0) ? 4361172093Sken "Blocks: " : "", (uintmax_t)maxsector + 1, 4362172093Sken (sizeonly == 0) ? ", " : "\n"); 4363172093Sken } else { 4364172093Sken fprintf(stdout, "%s%ju%s", (quiet == 0) ? 4365172093Sken "Last Block: " : "", (uintmax_t)maxsector, 4366172093Sken (sizeonly == 0) ? ", " : "\n"); 4367172093Sken } 4368172093Sken } 4369172093Sken if (sizeonly == 0) 4370172093Sken fprintf(stdout, "%s%u%s\n", (quiet == 0) ? 4371172093Sken "Block Length: " : "", block_len, (quiet == 0) ? 4372172093Sken " bytes" : ""); 4373172093Skenbailout: 4374172093Sken cam_freeccb(ccb); 4375172093Sken 4376172093Sken return (retval); 4377172093Sken} 4378172093Sken 4379199079Smavstatic int 4380216088Skensmpcmd(struct cam_device *device, int argc, char **argv, char *combinedopt, 4381216088Sken int retry_count, int timeout) 4382216088Sken{ 4383216088Sken int c, error; 4384216088Sken union ccb *ccb; 4385216088Sken uint8_t *smp_request = NULL, *smp_response = NULL; 4386216088Sken int request_size = 0, response_size = 0; 4387216088Sken int fd_request = 0, fd_response = 0; 4388216088Sken char *datastr = NULL; 4389216088Sken struct get_hook hook; 4390216088Sken int retval; 4391216088Sken int flags = 0; 4392216088Sken 4393216088Sken /* 4394216088Sken * Note that at the moment we don't support sending SMP CCBs to 4395216088Sken * devices that aren't probed by CAM. 4396216088Sken */ 4397216088Sken ccb = cam_getccb(device); 4398216088Sken if (ccb == NULL) { 4399216088Sken warnx("%s: error allocating CCB", __func__); 4400216088Sken return (1); 4401216088Sken } 4402216088Sken 4403216088Sken bzero(&(&ccb->ccb_h)[1], 4404216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 4405216088Sken 4406216088Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 4407216088Sken switch (c) { 4408216088Sken case 'R': 4409216088Sken arglist |= CAM_ARG_CMD_IN; 4410216088Sken response_size = strtol(optarg, NULL, 0); 4411216088Sken if (response_size <= 0) { 4412216088Sken warnx("invalid number of response bytes %d", 4413216088Sken response_size); 4414216088Sken error = 1; 4415216088Sken goto smpcmd_bailout; 4416216088Sken } 4417216088Sken hook.argc = argc - optind; 4418216088Sken hook.argv = argv + optind; 4419216088Sken hook.got = 0; 4420216088Sken optind++; 4421216088Sken datastr = cget(&hook, NULL); 4422216088Sken /* 4423216088Sken * If the user supplied "-" instead of a format, he 4424216088Sken * wants the data to be written to stdout. 4425216088Sken */ 4426216088Sken if ((datastr != NULL) 4427216088Sken && (datastr[0] == '-')) 4428216088Sken fd_response = 1; 4429216088Sken 4430216088Sken smp_response = (u_int8_t *)malloc(response_size); 4431216088Sken if (smp_response == NULL) { 4432216088Sken warn("can't malloc memory for SMP response"); 4433216088Sken error = 1; 4434216088Sken goto smpcmd_bailout; 4435216088Sken } 4436216088Sken break; 4437216088Sken case 'r': 4438216088Sken arglist |= CAM_ARG_CMD_OUT; 4439216088Sken request_size = strtol(optarg, NULL, 0); 4440216088Sken if (request_size <= 0) { 4441216088Sken warnx("invalid number of request bytes %d", 4442216088Sken request_size); 4443216088Sken error = 1; 4444216088Sken goto smpcmd_bailout; 4445216088Sken } 4446216088Sken hook.argc = argc - optind; 4447216088Sken hook.argv = argv + optind; 4448216088Sken hook.got = 0; 4449216088Sken datastr = cget(&hook, NULL); 4450216088Sken smp_request = (u_int8_t *)malloc(request_size); 4451216088Sken if (smp_request == NULL) { 4452216088Sken warn("can't malloc memory for SMP request"); 4453216088Sken error = 1; 4454216088Sken goto smpcmd_bailout; 4455216088Sken } 4456216088Sken bzero(smp_request, request_size); 4457216088Sken /* 4458216088Sken * If the user supplied "-" instead of a format, he 4459216088Sken * wants the data to be read from stdin. 4460216088Sken */ 4461216088Sken if ((datastr != NULL) 4462216088Sken && (datastr[0] == '-')) 4463216088Sken fd_request = 1; 4464216088Sken else 4465216088Sken buff_encode_visit(smp_request, request_size, 4466216088Sken datastr, 4467216088Sken iget, &hook); 4468216088Sken optind += hook.got; 4469216088Sken break; 4470216088Sken default: 4471216088Sken break; 4472216088Sken } 4473216088Sken } 4474216088Sken 4475216088Sken /* 4476216088Sken * If fd_data is set, and we're writing to the device, we need to 4477216088Sken * read the data the user wants written from stdin. 4478216088Sken */ 4479216088Sken if ((fd_request == 1) && (arglist & CAM_ARG_CMD_OUT)) { 4480216088Sken ssize_t amt_read; 4481216088Sken int amt_to_read = request_size; 4482216088Sken u_int8_t *buf_ptr = smp_request; 4483216088Sken 4484216088Sken for (amt_read = 0; amt_to_read > 0; 4485216088Sken amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) { 4486216088Sken if (amt_read == -1) { 4487216088Sken warn("error reading data from stdin"); 4488216088Sken error = 1; 4489216088Sken goto smpcmd_bailout; 4490216088Sken } 4491216088Sken amt_to_read -= amt_read; 4492216088Sken buf_ptr += amt_read; 4493216088Sken } 4494216088Sken } 4495216088Sken 4496216088Sken if (((arglist & CAM_ARG_CMD_IN) == 0) 4497216088Sken || ((arglist & CAM_ARG_CMD_OUT) == 0)) { 4498216088Sken warnx("%s: need both the request (-r) and response (-R) " 4499216088Sken "arguments", __func__); 4500216088Sken error = 1; 4501216088Sken goto smpcmd_bailout; 4502216088Sken } 4503216088Sken 4504216088Sken flags |= CAM_DEV_QFRZDIS; 4505216088Sken 4506216088Sken cam_fill_smpio(&ccb->smpio, 4507216088Sken /*retries*/ retry_count, 4508216088Sken /*cbfcnp*/ NULL, 4509216088Sken /*flags*/ flags, 4510216088Sken /*smp_request*/ smp_request, 4511216088Sken /*smp_request_len*/ request_size, 4512216088Sken /*smp_response*/ smp_response, 4513216088Sken /*smp_response_len*/ response_size, 4514216088Sken /*timeout*/ timeout ? timeout : 5000); 4515216088Sken 4516216088Sken ccb->smpio.flags = SMP_FLAG_NONE; 4517216088Sken 4518216088Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 4519216088Sken || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 4520228602Sdim const char warnstr[] = "error sending command"; 4521216088Sken 4522216088Sken if (retval < 0) 4523216088Sken warn(warnstr); 4524216088Sken else 4525216088Sken warnx(warnstr); 4526216088Sken 4527216088Sken if (arglist & CAM_ARG_VERBOSE) { 4528216088Sken cam_error_print(device, ccb, CAM_ESF_ALL, 4529216088Sken CAM_EPF_ALL, stderr); 4530216088Sken } 4531216088Sken } 4532216088Sken 4533216088Sken if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 4534216088Sken && (response_size > 0)) { 4535216088Sken if (fd_response == 0) { 4536216088Sken buff_decode_visit(smp_response, response_size, 4537216088Sken datastr, arg_put, NULL); 4538216088Sken fprintf(stdout, "\n"); 4539216088Sken } else { 4540216088Sken ssize_t amt_written; 4541216088Sken int amt_to_write = response_size; 4542216088Sken u_int8_t *buf_ptr = smp_response; 4543216088Sken 4544216088Sken for (amt_written = 0; (amt_to_write > 0) && 4545216088Sken (amt_written = write(STDOUT_FILENO, buf_ptr, 4546216088Sken amt_to_write)) > 0;){ 4547216088Sken amt_to_write -= amt_written; 4548216088Sken buf_ptr += amt_written; 4549216088Sken } 4550216088Sken if (amt_written == -1) { 4551216088Sken warn("error writing data to stdout"); 4552216088Sken error = 1; 4553216088Sken goto smpcmd_bailout; 4554216088Sken } else if ((amt_written == 0) 4555216088Sken && (amt_to_write > 0)) { 4556216088Sken warnx("only wrote %u bytes out of %u", 4557216088Sken response_size - amt_to_write, 4558216088Sken response_size); 4559216088Sken } 4560216088Sken } 4561216088Sken } 4562216088Skensmpcmd_bailout: 4563216088Sken if (ccb != NULL) 4564216088Sken cam_freeccb(ccb); 4565216088Sken 4566216088Sken if (smp_request != NULL) 4567216088Sken free(smp_request); 4568216088Sken 4569216088Sken if (smp_response != NULL) 4570216088Sken free(smp_response); 4571216088Sken 4572216088Sken return (error); 4573216088Sken} 4574216088Sken 4575216088Skenstatic int 4576216088Skensmpreportgeneral(struct cam_device *device, int argc, char **argv, 4577216088Sken char *combinedopt, int retry_count, int timeout) 4578216088Sken{ 4579216088Sken union ccb *ccb; 4580216088Sken struct smp_report_general_request *request = NULL; 4581216088Sken struct smp_report_general_response *response = NULL; 4582216088Sken struct sbuf *sb = NULL; 4583216088Sken int error = 0; 4584216088Sken int c, long_response = 0; 4585216088Sken int retval; 4586216088Sken 4587216088Sken /* 4588216088Sken * Note that at the moment we don't support sending SMP CCBs to 4589216088Sken * devices that aren't probed by CAM. 4590216088Sken */ 4591216088Sken ccb = cam_getccb(device); 4592216088Sken if (ccb == NULL) { 4593216088Sken warnx("%s: error allocating CCB", __func__); 4594216088Sken return (1); 4595216088Sken } 4596216088Sken 4597216088Sken bzero(&(&ccb->ccb_h)[1], 4598216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 4599216088Sken 4600216088Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 4601216088Sken switch (c) { 4602216088Sken case 'l': 4603216088Sken long_response = 1; 4604216088Sken break; 4605216088Sken default: 4606216088Sken break; 4607216088Sken } 4608216088Sken } 4609216088Sken request = malloc(sizeof(*request)); 4610216088Sken if (request == NULL) { 4611216088Sken warn("%s: unable to allocate %zd bytes", __func__, 4612216088Sken sizeof(*request)); 4613216088Sken error = 1; 4614216088Sken goto bailout; 4615216088Sken } 4616216088Sken 4617216088Sken response = malloc(sizeof(*response)); 4618216088Sken if (response == NULL) { 4619216088Sken warn("%s: unable to allocate %zd bytes", __func__, 4620216088Sken sizeof(*response)); 4621216088Sken error = 1; 4622216088Sken goto bailout; 4623216088Sken } 4624216088Sken 4625216088Skentry_long: 4626216088Sken smp_report_general(&ccb->smpio, 4627216088Sken retry_count, 4628216088Sken /*cbfcnp*/ NULL, 4629216088Sken request, 4630216088Sken /*request_len*/ sizeof(*request), 4631216088Sken (uint8_t *)response, 4632216088Sken /*response_len*/ sizeof(*response), 4633216088Sken /*long_response*/ long_response, 4634216088Sken timeout); 4635216088Sken 4636216088Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 4637216088Sken || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 4638228602Sdim const char warnstr[] = "error sending command"; 4639216088Sken 4640216088Sken if (retval < 0) 4641216088Sken warn(warnstr); 4642216088Sken else 4643216088Sken warnx(warnstr); 4644216088Sken 4645216088Sken if (arglist & CAM_ARG_VERBOSE) { 4646216088Sken cam_error_print(device, ccb, CAM_ESF_ALL, 4647216088Sken CAM_EPF_ALL, stderr); 4648216088Sken } 4649216088Sken error = 1; 4650216088Sken goto bailout; 4651216088Sken } 4652216088Sken 4653216088Sken /* 4654216088Sken * If the device supports the long response bit, try again and see 4655216088Sken * if we can get all of the data. 4656216088Sken */ 4657216088Sken if ((response->long_response & SMP_RG_LONG_RESPONSE) 4658216088Sken && (long_response == 0)) { 4659216088Sken ccb->ccb_h.status = CAM_REQ_INPROG; 4660216088Sken bzero(&(&ccb->ccb_h)[1], 4661216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 4662216088Sken long_response = 1; 4663216088Sken goto try_long; 4664216088Sken } 4665216088Sken 4666216088Sken /* 4667216088Sken * XXX KDM detect and decode SMP errors here. 4668216088Sken */ 4669216088Sken sb = sbuf_new_auto(); 4670216088Sken if (sb == NULL) { 4671216088Sken warnx("%s: error allocating sbuf", __func__); 4672216088Sken goto bailout; 4673216088Sken } 4674216088Sken 4675216088Sken smp_report_general_sbuf(response, sizeof(*response), sb); 4676216088Sken 4677216088Sken sbuf_finish(sb); 4678216088Sken 4679216088Sken printf("%s", sbuf_data(sb)); 4680216088Sken 4681216088Skenbailout: 4682216088Sken if (ccb != NULL) 4683216088Sken cam_freeccb(ccb); 4684216088Sken 4685216088Sken if (request != NULL) 4686216088Sken free(request); 4687216088Sken 4688216088Sken if (response != NULL) 4689216088Sken free(response); 4690216088Sken 4691216088Sken if (sb != NULL) 4692216088Sken sbuf_delete(sb); 4693216088Sken 4694216088Sken return (error); 4695216088Sken} 4696216088Sken 4697227081Sedstatic struct camcontrol_opts phy_ops[] = { 4698216088Sken {"nop", SMP_PC_PHY_OP_NOP, CAM_ARG_NONE, NULL}, 4699216088Sken {"linkreset", SMP_PC_PHY_OP_LINK_RESET, CAM_ARG_NONE, NULL}, 4700216088Sken {"hardreset", SMP_PC_PHY_OP_HARD_RESET, CAM_ARG_NONE, NULL}, 4701216088Sken {"disable", SMP_PC_PHY_OP_DISABLE, CAM_ARG_NONE, NULL}, 4702216088Sken {"clearerrlog", SMP_PC_PHY_OP_CLEAR_ERR_LOG, CAM_ARG_NONE, NULL}, 4703216088Sken {"clearaffiliation", SMP_PC_PHY_OP_CLEAR_AFFILIATON, CAM_ARG_NONE,NULL}, 4704216088Sken {"sataportsel", SMP_PC_PHY_OP_TRANS_SATA_PSS, CAM_ARG_NONE, NULL}, 4705216088Sken {"clearitnl", SMP_PC_PHY_OP_CLEAR_STP_ITN_LS, CAM_ARG_NONE, NULL}, 4706216088Sken {"setdevname", SMP_PC_PHY_OP_SET_ATT_DEV_NAME, CAM_ARG_NONE, NULL}, 4707216088Sken {NULL, 0, 0, NULL} 4708216088Sken}; 4709216088Sken 4710216088Skenstatic int 4711216088Skensmpphycontrol(struct cam_device *device, int argc, char **argv, 4712216088Sken char *combinedopt, int retry_count, int timeout) 4713216088Sken{ 4714216088Sken union ccb *ccb; 4715216088Sken struct smp_phy_control_request *request = NULL; 4716216088Sken struct smp_phy_control_response *response = NULL; 4717216088Sken int long_response = 0; 4718216088Sken int retval = 0; 4719216088Sken int phy = -1; 4720216088Sken uint32_t phy_operation = SMP_PC_PHY_OP_NOP; 4721216088Sken int phy_op_set = 0; 4722216088Sken uint64_t attached_dev_name = 0; 4723216088Sken int dev_name_set = 0; 4724216088Sken uint32_t min_plr = 0, max_plr = 0; 4725216088Sken uint32_t pp_timeout_val = 0; 4726216088Sken int slumber_partial = 0; 4727216088Sken int set_pp_timeout_val = 0; 4728216088Sken int c; 4729216088Sken 4730216088Sken /* 4731216088Sken * Note that at the moment we don't support sending SMP CCBs to 4732216088Sken * devices that aren't probed by CAM. 4733216088Sken */ 4734216088Sken ccb = cam_getccb(device); 4735216088Sken if (ccb == NULL) { 4736216088Sken warnx("%s: error allocating CCB", __func__); 4737216088Sken return (1); 4738216088Sken } 4739216088Sken 4740216088Sken bzero(&(&ccb->ccb_h)[1], 4741216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 4742216088Sken 4743216088Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 4744216088Sken switch (c) { 4745216088Sken case 'a': 4746216088Sken case 'A': 4747216088Sken case 's': 4748216088Sken case 'S': { 4749216088Sken int enable = -1; 4750216088Sken 4751216088Sken if (strcasecmp(optarg, "enable") == 0) 4752216088Sken enable = 1; 4753216088Sken else if (strcasecmp(optarg, "disable") == 0) 4754216088Sken enable = 2; 4755216088Sken else { 4756216088Sken warnx("%s: Invalid argument %s", __func__, 4757216088Sken optarg); 4758216088Sken retval = 1; 4759216088Sken goto bailout; 4760216088Sken } 4761216088Sken switch (c) { 4762216088Sken case 's': 4763216088Sken slumber_partial |= enable << 4764216088Sken SMP_PC_SAS_SLUMBER_SHIFT; 4765216088Sken break; 4766216088Sken case 'S': 4767216088Sken slumber_partial |= enable << 4768216088Sken SMP_PC_SAS_PARTIAL_SHIFT; 4769216088Sken break; 4770216088Sken case 'a': 4771216088Sken slumber_partial |= enable << 4772216088Sken SMP_PC_SATA_SLUMBER_SHIFT; 4773216088Sken break; 4774216088Sken case 'A': 4775216088Sken slumber_partial |= enable << 4776216088Sken SMP_PC_SATA_PARTIAL_SHIFT; 4777216088Sken break; 4778216088Sken default: 4779216088Sken warnx("%s: programmer error", __func__); 4780216088Sken retval = 1; 4781216088Sken goto bailout; 4782216088Sken break; /*NOTREACHED*/ 4783216088Sken } 4784216088Sken break; 4785216088Sken } 4786216088Sken case 'd': 4787216088Sken attached_dev_name = (uintmax_t)strtoumax(optarg, 4788216088Sken NULL,0); 4789216088Sken dev_name_set = 1; 4790216088Sken break; 4791216088Sken case 'l': 4792216088Sken long_response = 1; 4793216088Sken break; 4794216088Sken case 'm': 4795216088Sken /* 4796216088Sken * We don't do extensive checking here, so this 4797216088Sken * will continue to work when new speeds come out. 4798216088Sken */ 4799216088Sken min_plr = strtoul(optarg, NULL, 0); 4800216088Sken if ((min_plr == 0) 4801216088Sken || (min_plr > 0xf)) { 4802216088Sken warnx("%s: invalid link rate %x", 4803216088Sken __func__, min_plr); 4804216088Sken retval = 1; 4805216088Sken goto bailout; 4806216088Sken } 4807216088Sken break; 4808216088Sken case 'M': 4809216088Sken /* 4810216088Sken * We don't do extensive checking here, so this 4811216088Sken * will continue to work when new speeds come out. 4812216088Sken */ 4813216088Sken max_plr = strtoul(optarg, NULL, 0); 4814216088Sken if ((max_plr == 0) 4815216088Sken || (max_plr > 0xf)) { 4816216088Sken warnx("%s: invalid link rate %x", 4817216088Sken __func__, max_plr); 4818216088Sken retval = 1; 4819216088Sken goto bailout; 4820216088Sken } 4821216088Sken break; 4822216088Sken case 'o': { 4823216088Sken camcontrol_optret optreturn; 4824216088Sken cam_argmask argnums; 4825216088Sken const char *subopt; 4826216088Sken 4827216088Sken if (phy_op_set != 0) { 4828216088Sken warnx("%s: only one phy operation argument " 4829216088Sken "(-o) allowed", __func__); 4830216088Sken retval = 1; 4831216088Sken goto bailout; 4832216088Sken } 4833216088Sken 4834216088Sken phy_op_set = 1; 4835216088Sken 4836216088Sken /* 4837216088Sken * Allow the user to specify the phy operation 4838216088Sken * numerically, as well as with a name. This will 4839216088Sken * future-proof it a bit, so options that are added 4840216088Sken * in future specs can be used. 4841216088Sken */ 4842216088Sken if (isdigit(optarg[0])) { 4843216088Sken phy_operation = strtoul(optarg, NULL, 0); 4844216088Sken if ((phy_operation == 0) 4845216088Sken || (phy_operation > 0xff)) { 4846216088Sken warnx("%s: invalid phy operation %#x", 4847216088Sken __func__, phy_operation); 4848216088Sken retval = 1; 4849216088Sken goto bailout; 4850216088Sken } 4851216088Sken break; 4852216088Sken } 4853216088Sken optreturn = getoption(phy_ops, optarg, &phy_operation, 4854216088Sken &argnums, &subopt); 4855216088Sken 4856216088Sken if (optreturn == CC_OR_AMBIGUOUS) { 4857216088Sken warnx("%s: ambiguous option %s", __func__, 4858216088Sken optarg); 4859216088Sken usage(0); 4860216088Sken retval = 1; 4861216088Sken goto bailout; 4862216088Sken } else if (optreturn == CC_OR_NOT_FOUND) { 4863216088Sken warnx("%s: option %s not found", __func__, 4864216088Sken optarg); 4865216088Sken usage(0); 4866216088Sken retval = 1; 4867216088Sken goto bailout; 4868216088Sken } 4869216088Sken break; 4870216088Sken } 4871216088Sken case 'p': 4872216088Sken phy = atoi(optarg); 4873216088Sken break; 4874216088Sken case 'T': 4875216088Sken pp_timeout_val = strtoul(optarg, NULL, 0); 4876216088Sken if (pp_timeout_val > 15) { 4877216088Sken warnx("%s: invalid partial pathway timeout " 4878216088Sken "value %u, need a value less than 16", 4879216088Sken __func__, pp_timeout_val); 4880216088Sken retval = 1; 4881216088Sken goto bailout; 4882216088Sken } 4883216088Sken set_pp_timeout_val = 1; 4884216088Sken break; 4885216088Sken default: 4886216088Sken break; 4887216088Sken } 4888216088Sken } 4889216088Sken 4890216088Sken if (phy == -1) { 4891216088Sken warnx("%s: a PHY (-p phy) argument is required",__func__); 4892216088Sken retval = 1; 4893216088Sken goto bailout; 4894216088Sken } 4895216088Sken 4896216088Sken if (((dev_name_set != 0) 4897216088Sken && (phy_operation != SMP_PC_PHY_OP_SET_ATT_DEV_NAME)) 4898216088Sken || ((phy_operation == SMP_PC_PHY_OP_SET_ATT_DEV_NAME) 4899216088Sken && (dev_name_set == 0))) { 4900216088Sken warnx("%s: -d name and -o setdevname arguments both " 4901216088Sken "required to set device name", __func__); 4902216088Sken retval = 1; 4903216088Sken goto bailout; 4904216088Sken } 4905216088Sken 4906216088Sken request = malloc(sizeof(*request)); 4907216088Sken if (request == NULL) { 4908216088Sken warn("%s: unable to allocate %zd bytes", __func__, 4909216088Sken sizeof(*request)); 4910216088Sken retval = 1; 4911216088Sken goto bailout; 4912216088Sken } 4913216088Sken 4914216088Sken response = malloc(sizeof(*response)); 4915216088Sken if (response == NULL) { 4916216088Sken warn("%s: unable to allocate %zd bytes", __func__, 4917216088Sken sizeof(*request)); 4918216088Sken retval = 1; 4919216088Sken goto bailout; 4920216088Sken } 4921216088Sken 4922216088Sken smp_phy_control(&ccb->smpio, 4923216088Sken retry_count, 4924216088Sken /*cbfcnp*/ NULL, 4925216088Sken request, 4926216088Sken sizeof(*request), 4927216088Sken (uint8_t *)response, 4928216088Sken sizeof(*response), 4929216088Sken long_response, 4930216088Sken /*expected_exp_change_count*/ 0, 4931216088Sken phy, 4932216088Sken phy_operation, 4933216088Sken (set_pp_timeout_val != 0) ? 1 : 0, 4934216088Sken attached_dev_name, 4935216088Sken min_plr, 4936216088Sken max_plr, 4937216088Sken slumber_partial, 4938216088Sken pp_timeout_val, 4939216088Sken timeout); 4940216088Sken 4941216088Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 4942216088Sken || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 4943228602Sdim const char warnstr[] = "error sending command"; 4944216088Sken 4945216088Sken if (retval < 0) 4946216088Sken warn(warnstr); 4947216088Sken else 4948216088Sken warnx(warnstr); 4949216088Sken 4950216088Sken if (arglist & CAM_ARG_VERBOSE) { 4951216088Sken /* 4952216088Sken * Use CAM_EPF_NORMAL so we only get one line of 4953216088Sken * SMP command decoding. 4954216088Sken */ 4955216088Sken cam_error_print(device, ccb, CAM_ESF_ALL, 4956216088Sken CAM_EPF_NORMAL, stderr); 4957216088Sken } 4958216088Sken retval = 1; 4959216088Sken goto bailout; 4960216088Sken } 4961216088Sken 4962216088Sken /* XXX KDM print out something here for success? */ 4963216088Skenbailout: 4964216088Sken if (ccb != NULL) 4965216088Sken cam_freeccb(ccb); 4966216088Sken 4967216088Sken if (request != NULL) 4968216088Sken free(request); 4969216088Sken 4970216088Sken if (response != NULL) 4971216088Sken free(response); 4972216088Sken 4973216088Sken return (retval); 4974216088Sken} 4975216088Sken 4976216088Skenstatic int 4977216088Skensmpmaninfo(struct cam_device *device, int argc, char **argv, 4978216088Sken char *combinedopt, int retry_count, int timeout) 4979216088Sken{ 4980216088Sken union ccb *ccb; 4981216088Sken struct smp_report_manuf_info_request request; 4982216088Sken struct smp_report_manuf_info_response response; 4983216088Sken struct sbuf *sb = NULL; 4984216088Sken int long_response = 0; 4985216088Sken int retval = 0; 4986216088Sken int c; 4987216088Sken 4988216088Sken /* 4989216088Sken * Note that at the moment we don't support sending SMP CCBs to 4990216088Sken * devices that aren't probed by CAM. 4991216088Sken */ 4992216088Sken ccb = cam_getccb(device); 4993216088Sken if (ccb == NULL) { 4994216088Sken warnx("%s: error allocating CCB", __func__); 4995216088Sken return (1); 4996216088Sken } 4997216088Sken 4998216088Sken bzero(&(&ccb->ccb_h)[1], 4999216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 5000216088Sken 5001216088Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 5002216088Sken switch (c) { 5003216088Sken case 'l': 5004216088Sken long_response = 1; 5005216088Sken break; 5006216088Sken default: 5007216088Sken break; 5008216088Sken } 5009216088Sken } 5010216088Sken bzero(&request, sizeof(request)); 5011216088Sken bzero(&response, sizeof(response)); 5012216088Sken 5013216088Sken smp_report_manuf_info(&ccb->smpio, 5014216088Sken retry_count, 5015216088Sken /*cbfcnp*/ NULL, 5016216088Sken &request, 5017216088Sken sizeof(request), 5018216088Sken (uint8_t *)&response, 5019216088Sken sizeof(response), 5020216088Sken long_response, 5021216088Sken timeout); 5022216088Sken 5023216088Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 5024216088Sken || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 5025228602Sdim const char warnstr[] = "error sending command"; 5026216088Sken 5027216088Sken if (retval < 0) 5028216088Sken warn(warnstr); 5029216088Sken else 5030216088Sken warnx(warnstr); 5031216088Sken 5032216088Sken if (arglist & CAM_ARG_VERBOSE) { 5033216088Sken cam_error_print(device, ccb, CAM_ESF_ALL, 5034216088Sken CAM_EPF_ALL, stderr); 5035216088Sken } 5036216088Sken retval = 1; 5037216088Sken goto bailout; 5038216088Sken } 5039216088Sken 5040216088Sken sb = sbuf_new_auto(); 5041216088Sken if (sb == NULL) { 5042216088Sken warnx("%s: error allocating sbuf", __func__); 5043216088Sken goto bailout; 5044216088Sken } 5045216088Sken 5046216088Sken smp_report_manuf_info_sbuf(&response, sizeof(response), sb); 5047216088Sken 5048216088Sken sbuf_finish(sb); 5049216088Sken 5050216088Sken printf("%s", sbuf_data(sb)); 5051216088Sken 5052216088Skenbailout: 5053216088Sken 5054216088Sken if (ccb != NULL) 5055216088Sken cam_freeccb(ccb); 5056216088Sken 5057216088Sken if (sb != NULL) 5058216088Sken sbuf_delete(sb); 5059216088Sken 5060216088Sken return (retval); 5061216088Sken} 5062216088Sken 5063216088Skenstatic int 5064216088Skengetdevid(struct cam_devitem *item) 5065216088Sken{ 5066216088Sken int retval = 0; 5067216088Sken union ccb *ccb = NULL; 5068216088Sken 5069216088Sken struct cam_device *dev; 5070216088Sken 5071216088Sken dev = cam_open_btl(item->dev_match.path_id, 5072216088Sken item->dev_match.target_id, 5073216088Sken item->dev_match.target_lun, O_RDWR, NULL); 5074216088Sken 5075216088Sken if (dev == NULL) { 5076216088Sken warnx("%s", cam_errbuf); 5077216088Sken retval = 1; 5078216088Sken goto bailout; 5079216088Sken } 5080216088Sken 5081216361Sken item->device_id_len = 0; 5082216088Sken 5083216088Sken ccb = cam_getccb(dev); 5084216088Sken if (ccb == NULL) { 5085216088Sken warnx("%s: error allocating CCB", __func__); 5086216088Sken retval = 1; 5087216088Sken goto bailout; 5088216088Sken } 5089216088Sken 5090216088Sken bzero(&(&ccb->ccb_h)[1], 5091216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 5092216361Sken 5093216361Sken /* 5094216361Sken * On the first try, we just probe for the size of the data, and 5095216361Sken * then allocate that much memory and try again. 5096216361Sken */ 5097216361Skenretry: 5098223081Sgibbs ccb->ccb_h.func_code = XPT_DEV_ADVINFO; 5099216088Sken ccb->ccb_h.flags = CAM_DIR_IN; 5100223081Sgibbs ccb->cdai.flags = 0; 5101223081Sgibbs ccb->cdai.buftype = CDAI_TYPE_SCSI_DEVID; 5102223081Sgibbs ccb->cdai.bufsiz = item->device_id_len; 5103216361Sken if (item->device_id_len != 0) 5104223081Sgibbs ccb->cdai.buf = (uint8_t *)item->device_id; 5105216088Sken 5106216088Sken if (cam_send_ccb(dev, ccb) < 0) { 5107216088Sken warn("%s: error sending XPT_GDEV_ADVINFO CCB", __func__); 5108216088Sken retval = 1; 5109216088Sken goto bailout; 5110216088Sken } 5111216088Sken 5112216088Sken if (ccb->ccb_h.status != CAM_REQ_CMP) { 5113216088Sken warnx("%s: CAM status %#x", __func__, ccb->ccb_h.status); 5114216088Sken retval = 1; 5115216088Sken goto bailout; 5116216088Sken } 5117216088Sken 5118216361Sken if (item->device_id_len == 0) { 5119216361Sken /* 5120216361Sken * This is our first time through. Allocate the buffer, 5121216361Sken * and then go back to get the data. 5122216361Sken */ 5123223081Sgibbs if (ccb->cdai.provsiz == 0) { 5124216361Sken warnx("%s: invalid .provsiz field returned with " 5125216361Sken "XPT_GDEV_ADVINFO CCB", __func__); 5126216361Sken retval = 1; 5127216361Sken goto bailout; 5128216361Sken } 5129223081Sgibbs item->device_id_len = ccb->cdai.provsiz; 5130216361Sken item->device_id = malloc(item->device_id_len); 5131216361Sken if (item->device_id == NULL) { 5132216361Sken warn("%s: unable to allocate %d bytes", __func__, 5133216361Sken item->device_id_len); 5134216361Sken retval = 1; 5135216361Sken goto bailout; 5136216361Sken } 5137216361Sken ccb->ccb_h.status = CAM_REQ_INPROG; 5138216361Sken goto retry; 5139216361Sken } 5140216361Sken 5141216088Skenbailout: 5142216088Sken if (dev != NULL) 5143216088Sken cam_close_device(dev); 5144216088Sken 5145216088Sken if (ccb != NULL) 5146216088Sken cam_freeccb(ccb); 5147216088Sken 5148216088Sken return (retval); 5149216088Sken} 5150216088Sken 5151216088Sken/* 5152216088Sken * XXX KDM merge this code with getdevtree()? 5153216088Sken */ 5154216088Skenstatic int 5155216088Skenbuildbusdevlist(struct cam_devlist *devlist) 5156216088Sken{ 5157216088Sken union ccb ccb; 5158216088Sken int bufsize, fd = -1; 5159216088Sken struct dev_match_pattern *patterns; 5160216088Sken struct cam_devitem *item = NULL; 5161216088Sken int skip_device = 0; 5162216088Sken int retval = 0; 5163216088Sken 5164216088Sken if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) { 5165216088Sken warn("couldn't open %s", XPT_DEVICE); 5166216088Sken return(1); 5167216088Sken } 5168216088Sken 5169216088Sken bzero(&ccb, sizeof(union ccb)); 5170216088Sken 5171216088Sken ccb.ccb_h.path_id = CAM_XPT_PATH_ID; 5172216088Sken ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; 5173216088Sken ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; 5174216088Sken 5175216088Sken ccb.ccb_h.func_code = XPT_DEV_MATCH; 5176216088Sken bufsize = sizeof(struct dev_match_result) * 100; 5177216088Sken ccb.cdm.match_buf_len = bufsize; 5178216088Sken ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize); 5179216088Sken if (ccb.cdm.matches == NULL) { 5180216088Sken warnx("can't malloc memory for matches"); 5181216088Sken close(fd); 5182216088Sken return(1); 5183216088Sken } 5184216088Sken ccb.cdm.num_matches = 0; 5185216088Sken ccb.cdm.num_patterns = 2; 5186216088Sken ccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern) * 5187216088Sken ccb.cdm.num_patterns; 5188216088Sken 5189216088Sken patterns = (struct dev_match_pattern *)malloc(ccb.cdm.pattern_buf_len); 5190216088Sken if (patterns == NULL) { 5191216088Sken warnx("can't malloc memory for patterns"); 5192216088Sken retval = 1; 5193216088Sken goto bailout; 5194216088Sken } 5195216088Sken 5196216088Sken ccb.cdm.patterns = patterns; 5197216088Sken bzero(patterns, ccb.cdm.pattern_buf_len); 5198216088Sken 5199216088Sken patterns[0].type = DEV_MATCH_DEVICE; 5200216088Sken patterns[0].pattern.device_pattern.flags = DEV_MATCH_PATH; 5201216088Sken patterns[0].pattern.device_pattern.path_id = devlist->path_id; 5202216088Sken patterns[1].type = DEV_MATCH_PERIPH; 5203216088Sken patterns[1].pattern.periph_pattern.flags = PERIPH_MATCH_PATH; 5204216088Sken patterns[1].pattern.periph_pattern.path_id = devlist->path_id; 5205216088Sken 5206216088Sken /* 5207216088Sken * We do the ioctl multiple times if necessary, in case there are 5208216088Sken * more than 100 nodes in the EDT. 5209216088Sken */ 5210216088Sken do { 5211216088Sken unsigned int i; 5212216088Sken 5213216088Sken if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 5214216088Sken warn("error sending CAMIOCOMMAND ioctl"); 5215216088Sken retval = 1; 5216216088Sken goto bailout; 5217216088Sken } 5218216088Sken 5219216088Sken if ((ccb.ccb_h.status != CAM_REQ_CMP) 5220216088Sken || ((ccb.cdm.status != CAM_DEV_MATCH_LAST) 5221216088Sken && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { 5222216088Sken warnx("got CAM error %#x, CDM error %d\n", 5223216088Sken ccb.ccb_h.status, ccb.cdm.status); 5224216088Sken retval = 1; 5225216088Sken goto bailout; 5226216088Sken } 5227216088Sken 5228216088Sken for (i = 0; i < ccb.cdm.num_matches; i++) { 5229216088Sken switch (ccb.cdm.matches[i].type) { 5230216088Sken case DEV_MATCH_DEVICE: { 5231216088Sken struct device_match_result *dev_result; 5232216088Sken 5233216088Sken dev_result = 5234216088Sken &ccb.cdm.matches[i].result.device_result; 5235216088Sken 5236216361Sken if (dev_result->flags & 5237216361Sken DEV_RESULT_UNCONFIGURED) { 5238216088Sken skip_device = 1; 5239216088Sken break; 5240216088Sken } else 5241216088Sken skip_device = 0; 5242216088Sken 5243216088Sken item = malloc(sizeof(*item)); 5244216088Sken if (item == NULL) { 5245216088Sken warn("%s: unable to allocate %zd bytes", 5246216088Sken __func__, sizeof(*item)); 5247216088Sken retval = 1; 5248216088Sken goto bailout; 5249216088Sken } 5250216088Sken bzero(item, sizeof(*item)); 5251216088Sken bcopy(dev_result, &item->dev_match, 5252216088Sken sizeof(*dev_result)); 5253216088Sken STAILQ_INSERT_TAIL(&devlist->dev_queue, item, 5254216088Sken links); 5255216088Sken 5256216088Sken if (getdevid(item) != 0) { 5257216088Sken retval = 1; 5258216088Sken goto bailout; 5259216088Sken } 5260216088Sken break; 5261216088Sken } 5262216088Sken case DEV_MATCH_PERIPH: { 5263216088Sken struct periph_match_result *periph_result; 5264216088Sken 5265216088Sken periph_result = 5266216088Sken &ccb.cdm.matches[i].result.periph_result; 5267216088Sken 5268216088Sken if (skip_device != 0) 5269216088Sken break; 5270216088Sken item->num_periphs++; 5271216088Sken item->periph_matches = realloc( 5272216088Sken item->periph_matches, 5273216088Sken item->num_periphs * 5274216088Sken sizeof(struct periph_match_result)); 5275216088Sken if (item->periph_matches == NULL) { 5276216088Sken warn("%s: error allocating periph " 5277216088Sken "list", __func__); 5278216088Sken retval = 1; 5279216088Sken goto bailout; 5280216088Sken } 5281216088Sken bcopy(periph_result, &item->periph_matches[ 5282216088Sken item->num_periphs - 1], 5283216088Sken sizeof(*periph_result)); 5284216088Sken break; 5285216088Sken } 5286216088Sken default: 5287216088Sken fprintf(stderr, "%s: unexpected match " 5288216088Sken "type %d\n", __func__, 5289216088Sken ccb.cdm.matches[i].type); 5290216088Sken retval = 1; 5291216088Sken goto bailout; 5292216088Sken break; /*NOTREACHED*/ 5293216088Sken } 5294216088Sken } 5295216088Sken } while ((ccb.ccb_h.status == CAM_REQ_CMP) 5296216088Sken && (ccb.cdm.status == CAM_DEV_MATCH_MORE)); 5297216088Skenbailout: 5298216088Sken 5299216088Sken if (fd != -1) 5300216088Sken close(fd); 5301216088Sken 5302216088Sken free(patterns); 5303216088Sken 5304216088Sken free(ccb.cdm.matches); 5305216088Sken 5306216088Sken if (retval != 0) 5307216088Sken freebusdevlist(devlist); 5308216088Sken 5309216088Sken return (retval); 5310216088Sken} 5311216088Sken 5312216088Skenstatic void 5313216088Skenfreebusdevlist(struct cam_devlist *devlist) 5314216088Sken{ 5315216088Sken struct cam_devitem *item, *item2; 5316216088Sken 5317216088Sken STAILQ_FOREACH_SAFE(item, &devlist->dev_queue, links, item2) { 5318216088Sken STAILQ_REMOVE(&devlist->dev_queue, item, cam_devitem, 5319216088Sken links); 5320216088Sken free(item->device_id); 5321216088Sken free(item->periph_matches); 5322216088Sken free(item); 5323216088Sken } 5324216088Sken} 5325216088Sken 5326216088Skenstatic struct cam_devitem * 5327216088Skenfindsasdevice(struct cam_devlist *devlist, uint64_t sasaddr) 5328216088Sken{ 5329216088Sken struct cam_devitem *item; 5330216088Sken 5331216088Sken STAILQ_FOREACH(item, &devlist->dev_queue, links) { 5332216088Sken uint8_t *item_addr; 5333216088Sken 5334216088Sken /* 5335216088Sken * XXX KDM look for LUN IDs as well? 5336216088Sken */ 5337223081Sgibbs item_addr = scsi_get_devid(item->device_id, 5338223081Sgibbs item->device_id_len, 5339223081Sgibbs scsi_devid_is_sas_target); 5340216088Sken if (item_addr == NULL) 5341216088Sken continue; 5342216088Sken 5343216088Sken if (scsi_8btou64(item_addr) == sasaddr) 5344216088Sken return (item); 5345216088Sken } 5346216088Sken 5347216088Sken return (NULL); 5348216088Sken} 5349216088Sken 5350216088Skenstatic int 5351216088Skensmpphylist(struct cam_device *device, int argc, char **argv, 5352216088Sken char *combinedopt, int retry_count, int timeout) 5353216088Sken{ 5354216088Sken struct smp_report_general_request *rgrequest = NULL; 5355216088Sken struct smp_report_general_response *rgresponse = NULL; 5356216088Sken struct smp_discover_request *disrequest = NULL; 5357216088Sken struct smp_discover_response *disresponse = NULL; 5358216088Sken struct cam_devlist devlist; 5359216088Sken union ccb *ccb; 5360216088Sken int long_response = 0; 5361216088Sken int num_phys = 0; 5362216088Sken int quiet = 0; 5363216088Sken int retval; 5364216088Sken int i, c; 5365216088Sken 5366216088Sken /* 5367216088Sken * Note that at the moment we don't support sending SMP CCBs to 5368216088Sken * devices that aren't probed by CAM. 5369216088Sken */ 5370216088Sken ccb = cam_getccb(device); 5371216088Sken if (ccb == NULL) { 5372216088Sken warnx("%s: error allocating CCB", __func__); 5373216088Sken return (1); 5374216088Sken } 5375216088Sken 5376216088Sken bzero(&(&ccb->ccb_h)[1], 5377216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 5378216088Sken 5379216088Sken rgrequest = malloc(sizeof(*rgrequest)); 5380216088Sken if (rgrequest == NULL) { 5381216088Sken warn("%s: unable to allocate %zd bytes", __func__, 5382216088Sken sizeof(*rgrequest)); 5383216088Sken retval = 1; 5384216088Sken goto bailout; 5385216088Sken } 5386216088Sken 5387216088Sken rgresponse = malloc(sizeof(*rgresponse)); 5388216088Sken if (rgresponse == NULL) { 5389216088Sken warn("%s: unable to allocate %zd bytes", __func__, 5390216088Sken sizeof(*rgresponse)); 5391216088Sken retval = 1; 5392216088Sken goto bailout; 5393216088Sken } 5394216088Sken 5395216088Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 5396216088Sken switch (c) { 5397216088Sken case 'l': 5398216088Sken long_response = 1; 5399216088Sken break; 5400216088Sken case 'q': 5401216088Sken quiet = 1; 5402216088Sken break; 5403216088Sken default: 5404216088Sken break; 5405216088Sken } 5406216088Sken } 5407216088Sken 5408216088Sken smp_report_general(&ccb->smpio, 5409216088Sken retry_count, 5410216088Sken /*cbfcnp*/ NULL, 5411216088Sken rgrequest, 5412216088Sken /*request_len*/ sizeof(*rgrequest), 5413216088Sken (uint8_t *)rgresponse, 5414216088Sken /*response_len*/ sizeof(*rgresponse), 5415216088Sken /*long_response*/ long_response, 5416216088Sken timeout); 5417216088Sken 5418216088Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 5419216088Sken 5420216088Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 5421216088Sken || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 5422228602Sdim const char warnstr[] = "error sending command"; 5423216088Sken 5424216088Sken if (retval < 0) 5425216088Sken warn(warnstr); 5426216088Sken else 5427216088Sken warnx(warnstr); 5428216088Sken 5429216088Sken if (arglist & CAM_ARG_VERBOSE) { 5430216088Sken cam_error_print(device, ccb, CAM_ESF_ALL, 5431216088Sken CAM_EPF_ALL, stderr); 5432216088Sken } 5433216088Sken retval = 1; 5434216088Sken goto bailout; 5435216088Sken } 5436216088Sken 5437216088Sken num_phys = rgresponse->num_phys; 5438216088Sken 5439216088Sken if (num_phys == 0) { 5440216088Sken if (quiet == 0) 5441216088Sken fprintf(stdout, "%s: No Phys reported\n", __func__); 5442216088Sken retval = 1; 5443216088Sken goto bailout; 5444216088Sken } 5445216088Sken 5446216088Sken STAILQ_INIT(&devlist.dev_queue); 5447216088Sken devlist.path_id = device->path_id; 5448216088Sken 5449216088Sken retval = buildbusdevlist(&devlist); 5450216088Sken if (retval != 0) 5451216088Sken goto bailout; 5452216088Sken 5453216088Sken if (quiet == 0) { 5454216088Sken fprintf(stdout, "%d PHYs:\n", num_phys); 5455216088Sken fprintf(stdout, "PHY Attached SAS Address\n"); 5456216088Sken } 5457216088Sken 5458216088Sken disrequest = malloc(sizeof(*disrequest)); 5459216088Sken if (disrequest == NULL) { 5460216088Sken warn("%s: unable to allocate %zd bytes", __func__, 5461216088Sken sizeof(*disrequest)); 5462216088Sken retval = 1; 5463216088Sken goto bailout; 5464216088Sken } 5465216088Sken 5466216088Sken disresponse = malloc(sizeof(*disresponse)); 5467216088Sken if (disresponse == NULL) { 5468216088Sken warn("%s: unable to allocate %zd bytes", __func__, 5469216088Sken sizeof(*disresponse)); 5470216088Sken retval = 1; 5471216088Sken goto bailout; 5472216088Sken } 5473216088Sken 5474216088Sken for (i = 0; i < num_phys; i++) { 5475216088Sken struct cam_devitem *item; 5476216088Sken struct device_match_result *dev_match; 5477216088Sken char vendor[16], product[48], revision[16]; 5478216088Sken char tmpstr[256]; 5479216088Sken int j; 5480216088Sken 5481216088Sken bzero(&(&ccb->ccb_h)[1], 5482216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 5483216088Sken 5484216088Sken ccb->ccb_h.status = CAM_REQ_INPROG; 5485216088Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 5486216088Sken 5487216088Sken smp_discover(&ccb->smpio, 5488216088Sken retry_count, 5489216088Sken /*cbfcnp*/ NULL, 5490216088Sken disrequest, 5491216088Sken sizeof(*disrequest), 5492216088Sken (uint8_t *)disresponse, 5493216088Sken sizeof(*disresponse), 5494216088Sken long_response, 5495216088Sken /*ignore_zone_group*/ 0, 5496216088Sken /*phy*/ i, 5497216088Sken timeout); 5498216088Sken 5499216088Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 5500216088Sken || (((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 5501216088Sken && (disresponse->function_result != SMP_FR_PHY_VACANT))) { 5502228602Sdim const char warnstr[] = "error sending command"; 5503216088Sken 5504216088Sken if (retval < 0) 5505216088Sken warn(warnstr); 5506216088Sken else 5507216088Sken warnx(warnstr); 5508216088Sken 5509216088Sken if (arglist & CAM_ARG_VERBOSE) { 5510216088Sken cam_error_print(device, ccb, CAM_ESF_ALL, 5511216088Sken CAM_EPF_ALL, stderr); 5512216088Sken } 5513216088Sken retval = 1; 5514216088Sken goto bailout; 5515216088Sken } 5516216088Sken 5517216088Sken if (disresponse->function_result == SMP_FR_PHY_VACANT) { 5518216088Sken if (quiet == 0) 5519216088Sken fprintf(stdout, "%3d <vacant>\n", i); 5520216088Sken continue; 5521216088Sken } 5522216088Sken 5523216088Sken item = findsasdevice(&devlist, 5524216088Sken scsi_8btou64(disresponse->attached_sas_address)); 5525216088Sken 5526216088Sken if ((quiet == 0) 5527216088Sken || (item != NULL)) { 5528216088Sken fprintf(stdout, "%3d 0x%016jx", i, 5529216088Sken (uintmax_t)scsi_8btou64( 5530216088Sken disresponse->attached_sas_address)); 5531216088Sken if (item == NULL) { 5532216088Sken fprintf(stdout, "\n"); 5533216088Sken continue; 5534216088Sken } 5535216088Sken } else if (quiet != 0) 5536216088Sken continue; 5537216088Sken 5538216088Sken dev_match = &item->dev_match; 5539216088Sken 5540216088Sken if (dev_match->protocol == PROTO_SCSI) { 5541216088Sken cam_strvis(vendor, dev_match->inq_data.vendor, 5542216088Sken sizeof(dev_match->inq_data.vendor), 5543216088Sken sizeof(vendor)); 5544216088Sken cam_strvis(product, dev_match->inq_data.product, 5545216088Sken sizeof(dev_match->inq_data.product), 5546216088Sken sizeof(product)); 5547216088Sken cam_strvis(revision, dev_match->inq_data.revision, 5548216088Sken sizeof(dev_match->inq_data.revision), 5549216088Sken sizeof(revision)); 5550216088Sken sprintf(tmpstr, "<%s %s %s>", vendor, product, 5551216088Sken revision); 5552216088Sken } else if ((dev_match->protocol == PROTO_ATA) 5553216088Sken || (dev_match->protocol == PROTO_SATAPM)) { 5554216088Sken cam_strvis(product, dev_match->ident_data.model, 5555216088Sken sizeof(dev_match->ident_data.model), 5556216088Sken sizeof(product)); 5557216088Sken cam_strvis(revision, dev_match->ident_data.revision, 5558216088Sken sizeof(dev_match->ident_data.revision), 5559216088Sken sizeof(revision)); 5560216088Sken sprintf(tmpstr, "<%s %s>", product, revision); 5561216088Sken } else { 5562216088Sken sprintf(tmpstr, "<>"); 5563216088Sken } 5564216088Sken fprintf(stdout, " %-33s ", tmpstr); 5565216088Sken 5566216088Sken /* 5567216088Sken * If we have 0 periphs, that's a bug... 5568216088Sken */ 5569216088Sken if (item->num_periphs == 0) { 5570216088Sken fprintf(stdout, "\n"); 5571216088Sken continue; 5572216088Sken } 5573216088Sken 5574216088Sken fprintf(stdout, "("); 5575216088Sken for (j = 0; j < item->num_periphs; j++) { 5576216088Sken if (j > 0) 5577216088Sken fprintf(stdout, ","); 5578216088Sken 5579216088Sken fprintf(stdout, "%s%d", 5580216088Sken item->periph_matches[j].periph_name, 5581216088Sken item->periph_matches[j].unit_number); 5582216088Sken 5583216088Sken } 5584216088Sken fprintf(stdout, ")\n"); 5585216088Sken } 5586216088Skenbailout: 5587216088Sken if (ccb != NULL) 5588216088Sken cam_freeccb(ccb); 5589216088Sken 5590216088Sken free(rgrequest); 5591216088Sken 5592216088Sken free(rgresponse); 5593216088Sken 5594216088Sken free(disrequest); 5595216088Sken 5596216088Sken free(disresponse); 5597216088Sken 5598216088Sken freebusdevlist(&devlist); 5599216088Sken 5600216088Sken return (retval); 5601216088Sken} 5602216088Sken 5603216088Skenstatic int 5604199079Smavatapm(struct cam_device *device, int argc, char **argv, 5605199079Smav char *combinedopt, int retry_count, int timeout) 5606199079Smav{ 5607199079Smav union ccb *ccb; 5608199079Smav int retval = 0; 5609199079Smav int t = -1; 5610199101Smav int c; 5611199079Smav u_char cmd, sc; 5612199079Smav 5613199079Smav ccb = cam_getccb(device); 5614199079Smav 5615199079Smav if (ccb == NULL) { 5616199079Smav warnx("%s: error allocating ccb", __func__); 5617199079Smav return (1); 5618199079Smav } 5619199079Smav 5620199079Smav while ((c = getopt(argc, argv, combinedopt)) != -1) { 5621199079Smav switch (c) { 5622199079Smav case 't': 5623199079Smav t = atoi(optarg); 5624199079Smav break; 5625199079Smav default: 5626199079Smav break; 5627199079Smav } 5628199079Smav } 5629199079Smav if (strcmp(argv[1], "idle") == 0) { 5630199079Smav if (t == -1) 5631199079Smav cmd = ATA_IDLE_IMMEDIATE; 5632199079Smav else 5633199079Smav cmd = ATA_IDLE_CMD; 5634199079Smav } else if (strcmp(argv[1], "standby") == 0) { 5635199079Smav if (t == -1) 5636199079Smav cmd = ATA_STANDBY_IMMEDIATE; 5637199079Smav else 5638199079Smav cmd = ATA_STANDBY_CMD; 5639199079Smav } else { 5640199079Smav cmd = ATA_SLEEP; 5641199079Smav t = -1; 5642199079Smav } 5643214807Sbrucec 5644199079Smav if (t < 0) 5645199079Smav sc = 0; 5646199079Smav else if (t <= (240 * 5)) 5647214807Sbrucec sc = (t + 4) / 5; 5648214807Sbrucec else if (t <= (252 * 5)) 5649214781Sbrucec /* special encoding for 21 minutes */ 5650214781Sbrucec sc = 252; 5651199079Smav else if (t <= (11 * 30 * 60)) 5652214807Sbrucec sc = (t - 1) / (30 * 60) + 241; 5653199079Smav else 5654199079Smav sc = 253; 5655214781Sbrucec 5656199079Smav cam_fill_ataio(&ccb->ataio, 5657199079Smav retry_count, 5658199079Smav NULL, 5659199079Smav /*flags*/CAM_DIR_NONE, 5660199079Smav MSG_SIMPLE_Q_TAG, 5661199079Smav /*data_ptr*/NULL, 5662199079Smav /*dxfer_len*/0, 5663199079Smav timeout ? timeout : 30 * 1000); 5664199079Smav ata_28bit_cmd(&ccb->ataio, cmd, 0, 0, sc); 5665199079Smav 5666199079Smav /* Disable freezing the device queue */ 5667199079Smav ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 5668199079Smav 5669199079Smav if (arglist & CAM_ARG_ERR_RECOVER) 5670199079Smav ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 5671199079Smav 5672199079Smav if (cam_send_ccb(device, ccb) < 0) { 5673199079Smav warn("error sending command"); 5674199079Smav 5675199079Smav if (arglist & CAM_ARG_VERBOSE) 5676199079Smav cam_error_print(device, ccb, CAM_ESF_ALL, 5677199079Smav CAM_EPF_ALL, stderr); 5678199079Smav 5679199079Smav retval = 1; 5680199079Smav goto bailout; 5681199079Smav } 5682199079Smav 5683199079Smav if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 5684199079Smav cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); 5685199079Smav retval = 1; 5686199079Smav goto bailout; 5687199079Smav } 5688199079Smavbailout: 5689199079Smav cam_freeccb(ccb); 5690199079Smav return (retval); 5691199079Smav} 5692199079Smav 569389471Sjoerg#endif /* MINIMALISTIC */ 569460767Sken 5695214321Smavvoid 569646938Skenusage(int verbose) 569739214Sgibbs{ 569861228Sken fprintf(verbose ? stdout : stderr, 569946938Sken"usage: camcontrol <command> [device id][generic args][command args]\n" 570089521Sjoerg" camcontrol devlist [-v]\n" 570189471Sjoerg#ifndef MINIMALISTIC 570246938Sken" camcontrol periphlist [dev_id][-n dev_name] [-u unit]\n" 570346938Sken" camcontrol tur [dev_id][generic args]\n" 570446938Sken" camcontrol inquiry [dev_id][generic args] [-D] [-S] [-R]\n" 5705202694Smav" camcontrol identify [dev_id][generic args] [-v]\n" 5706161506Sken" camcontrol reportluns [dev_id][generic args] [-c] [-l] [-r report]\n" 5707172093Sken" camcontrol readcap [dev_id][generic args] [-b] [-h] [-H] [-N]\n" 5708172093Sken" [-q] [-s]\n" 570946938Sken" camcontrol start [dev_id][generic args]\n" 571046938Sken" camcontrol stop [dev_id][generic args]\n" 5711103033Smdodd" camcontrol load [dev_id][generic args]\n" 571246938Sken" camcontrol eject [dev_id][generic args]\n" 571389471Sjoerg#endif /* MINIMALISTIC */ 571489515Sken" camcontrol rescan <all | bus[:target:lun]>\n" 571589515Sken" camcontrol reset <all | bus[:target:lun]>\n" 571689471Sjoerg#ifndef MINIMALISTIC 571746938Sken" camcontrol defects [dev_id][generic args] <-f format> [-P][-G]\n" 571864382Skbyanc" camcontrol modepage [dev_id][generic args] <-m page | -l>\n" 571964382Skbyanc" [-P pagectl][-e | -b][-d]\n" 5720196831Smav" camcontrol cmd [dev_id][generic args]\n" 5721196831Smav" <-a cmd [args] | -c cmd [args]>\n" 5722207498Smav" [-d] [-f] [-i len fmt|-o len fmt [args]] [-r fmt]\n" 5723216088Sken" camcontrol smpcmd [dev_id][generic args]\n" 5724216088Sken" <-r len fmt [args]> <-R len fmt [args]>\n" 5725216088Sken" camcontrol smprg [dev_id][generic args][-l]\n" 5726216088Sken" camcontrol smppc [dev_id][generic args] <-p phy> [-l]\n" 5727216088Sken" [-o operation][-d name][-m rate][-M rate]\n" 5728216088Sken" [-T pp_timeout][-a enable|disable]\n" 5729216088Sken" [-A enable|disable][-s enable|disable]\n" 5730216088Sken" [-S enable|disable]\n" 5731216088Sken" camcontrol smpphylist [dev_id][generic args][-l][-q]\n" 5732216088Sken" camcontrol smpmaninfo [dev_id][generic args][-l]\n" 5733107966Snjl" camcontrol debug [-I][-P][-T][-S][-X][-c]\n" 5734107966Snjl" <all|bus[:target[:lun]]|off>\n" 573546938Sken" camcontrol tags [dev_id][generic args] [-N tags] [-q] [-v]\n" 573646938Sken" camcontrol negotiate [dev_id][generic args] [-a][-c]\n" 5737199821Smav" [-D <enable|disable>][-M mode][-O offset]\n" 5738199821Smav" [-q][-R syncrate][-v][-T <enable|disable>]\n" 573946938Sken" [-U][-W bus_width]\n" 5740144134Sken" camcontrol format [dev_id][generic args][-q][-r][-w][-y]\n" 5741199079Smav" camcontrol idle [dev_id][generic args][-t time]\n" 5742199079Smav" camcontrol standby [dev_id][generic args][-t time]\n" 5743199079Smav" camcontrol sleep [dev_id][generic args]\n" 5744227961Semaste" camcontrol fwdownload [dev_id][generic args] <-f fw_image> [-y][-s]\n" 574589471Sjoerg#endif /* MINIMALISTIC */ 574646938Sken" camcontrol help\n"); 574746938Sken if (!verbose) 574846938Sken return; 574989471Sjoerg#ifndef MINIMALISTIC 575061228Sken fprintf(stdout, 575139214Sgibbs"Specify one of the following options:\n" 575239214Sgibbs"devlist list all CAM devices\n" 575339214Sgibbs"periphlist list all CAM peripheral drivers attached to a device\n" 575439214Sgibbs"tur send a test unit ready to the named device\n" 575539214Sgibbs"inquiry send a SCSI inquiry command to the named device\n" 5756195534Sscottl"identify send a ATA identify command to the named device\n" 5757161506Sken"reportluns send a SCSI report luns command to the device\n" 5758172093Sken"readcap send a SCSI read capacity command to the device\n" 575939214Sgibbs"start send a Start Unit command to the device\n" 576039214Sgibbs"stop send a Stop Unit command to the device\n" 5761103033Smdodd"load send a Start Unit command to the device with the load bit set\n" 576239214Sgibbs"eject send a Stop Unit command to the device with the eject bit set\n" 576389515Sken"rescan rescan all busses, the given bus, or bus:target:lun\n" 576489515Sken"reset reset all busses, the given bus, or bus:target:lun\n" 576539214Sgibbs"defects read the defect list of the specified device\n" 576639214Sgibbs"modepage display or edit (-e) the given mode page\n" 5767216088Sken"cmd send the given SCSI command, may need -i or -o as well\n" 5768216088Sken"smpcmd send the given SMP command, requires -o and -i\n" 5769216088Sken"smprg send the SMP Report General command\n" 5770216088Sken"smppc send the SMP PHY Control command, requires -p\n" 5771216088Sken"smpphylist display phys attached to a SAS expander\n" 5772216088Sken"smpmaninfo send the SMP Report Manufacturer Info command\n" 577339214Sgibbs"debug turn debugging on/off for a bus, target, or lun, or all devices\n" 577446581Sken"tags report or set the number of transaction slots for a device\n" 577546581Sken"negotiate report or set device negotiation parameters\n" 577660767Sken"format send the SCSI FORMAT UNIT command to the named device\n" 5777199079Smav"idle send the ATA IDLE command to the named device\n" 5778199079Smav"standby send the ATA STANDBY command to the named device\n" 5779199079Smav"sleep send the ATA SLEEP command to the named device\n" 5780227961Semaste"fwdownload program firmware of the named device with the given image" 578146938Sken"help this message\n" 578246938Sken"Device Identifiers:\n" 578346938Sken"bus:target specify the bus and target, lun defaults to 0\n" 578446938Sken"bus:target:lun specify the bus, target and lun\n" 578546938Sken"deviceUNIT specify the device name, like \"da4\" or \"cd2\"\n" 578639214Sgibbs"Generic arguments:\n" 578739214Sgibbs"-v be verbose, print out sense information\n" 578839214Sgibbs"-t timeout command timeout in seconds, overrides default timeout\n" 578961233Sken"-n dev_name specify device name, e.g. \"da\", \"cd\"\n" 579061233Sken"-u unit specify unit number, e.g. \"0\", \"5\"\n" 579139214Sgibbs"-E have the kernel attempt to perform SCSI error recovery\n" 579239214Sgibbs"-C count specify the SCSI command retry count (needs -E to work)\n" 579339214Sgibbs"modepage arguments:\n" 579464468Skbyanc"-l list all available mode pages\n" 579546581Sken"-m page specify the mode page to view or edit\n" 579639214Sgibbs"-e edit the specified mode page\n" 579764382Skbyanc"-b force view to binary mode\n" 579846581Sken"-d disable block descriptors for mode sense\n" 579939214Sgibbs"-P pgctl page control field 0-3\n" 580039214Sgibbs"defects arguments:\n" 580139214Sgibbs"-f format specify defect list format (block, bfi or phys)\n" 580239214Sgibbs"-G get the grown defect list\n" 5803229778Suqs"-P get the permanent defect list\n" 580439214Sgibbs"inquiry arguments:\n" 580539214Sgibbs"-D get the standard inquiry data\n" 580639214Sgibbs"-S get the serial number\n" 580739214Sgibbs"-R get the transfer rate, etc.\n" 5808161506Sken"reportluns arguments:\n" 5809161506Sken"-c only report a count of available LUNs\n" 5810161506Sken"-l only print out luns, and not a count\n" 5811161506Sken"-r <reporttype> specify \"default\", \"wellknown\" or \"all\"\n" 5812172093Sken"readcap arguments\n" 5813172093Sken"-b only report the blocksize\n" 5814172093Sken"-h human readable device size, base 2\n" 5815172093Sken"-H human readable device size, base 10\n" 5816172093Sken"-N print the number of blocks instead of last block\n" 5817172093Sken"-q quiet, print numbers only\n" 5818172093Sken"-s only report the last block/device size\n" 581939214Sgibbs"cmd arguments:\n" 582039214Sgibbs"-c cdb [args] specify the SCSI CDB\n" 582139214Sgibbs"-i len fmt specify input data and input data format\n" 582239214Sgibbs"-o len fmt [args] specify output data and output data fmt\n" 5823216088Sken"smpcmd arguments:\n" 5824216088Sken"-r len fmt [args] specify the SMP command to be sent\n" 5825216088Sken"-R len fmt [args] specify SMP response format\n" 5826216088Sken"smprg arguments:\n" 5827216088Sken"-l specify the long response format\n" 5828216088Sken"smppc arguments:\n" 5829216088Sken"-p phy specify the PHY to operate on\n" 5830216088Sken"-l specify the long request/response format\n" 5831216088Sken"-o operation specify the phy control operation\n" 5832216088Sken"-d name set the attached device name\n" 5833216088Sken"-m rate set the minimum physical link rate\n" 5834216088Sken"-M rate set the maximum physical link rate\n" 5835216088Sken"-T pp_timeout set the partial pathway timeout value\n" 5836216088Sken"-a enable|disable enable or disable SATA slumber\n" 5837216088Sken"-A enable|disable enable or disable SATA partial phy power\n" 5838216088Sken"-s enable|disable enable or disable SAS slumber\n" 5839216088Sken"-S enable|disable enable or disable SAS partial phy power\n" 5840216088Sken"smpphylist arguments:\n" 5841216088Sken"-l specify the long response format\n" 5842216088Sken"-q only print phys with attached devices\n" 5843216088Sken"smpmaninfo arguments:\n" 5844216088Sken"-l specify the long response format\n" 584539214Sgibbs"debug arguments:\n" 584639214Sgibbs"-I CAM_DEBUG_INFO -- scsi commands, errors, data\n" 584739214Sgibbs"-T CAM_DEBUG_TRACE -- routine flow tracking\n" 584839903Sken"-S CAM_DEBUG_SUBTRACE -- internal routine command flow\n" 584946581Sken"-c CAM_DEBUG_CDB -- print out SCSI CDBs only\n" 585046581Sken"tags arguments:\n" 585146581Sken"-N tags specify the number of tags to use for this device\n" 585246581Sken"-q be quiet, don't report the number of tags\n" 585346581Sken"-v report a number of tag-related parameters\n" 585446581Sken"negotiate arguments:\n" 585546581Sken"-a send a test unit ready after negotiation\n" 585646581Sken"-c report/set current negotiation settings\n" 585746581Sken"-D <arg> \"enable\" or \"disable\" disconnection\n" 5858199821Smav"-M mode set ATA mode\n" 585946581Sken"-O offset set command delay offset\n" 586046581Sken"-q be quiet, don't report anything\n" 586146581Sken"-R syncrate synchronization rate in MHz\n" 586246581Sken"-T <arg> \"enable\" or \"disable\" tagged queueing\n" 586346581Sken"-U report/set user negotiation settings\n" 586446581Sken"-W bus_width set the bus width in bits (8, 16 or 32)\n" 586560767Sken"-v also print a Path Inquiry CCB for the controller\n" 586660767Sken"format arguments:\n" 586760767Sken"-q be quiet, don't print status messages\n" 5868144134Sken"-r run in report only mode\n" 586960767Sken"-w don't send immediate format command\n" 5870199079Smav"-y don't ask any questions\n" 5871199079Smav"idle/standby arguments:\n" 5872227961Semaste"-t <arg> number of seconds before respective state.\n" 5873227961Semaste"fwdownload arguments:\n" 5874227961Semaste"-f fw_image path to firmware image file\n" 5875227961Semaste"-y don't ask any questions\n" 5876227961Semaste"-s run in simulation mode\n" 5877227961Semaste"-v print info for every firmware segment sent to device\n"); 587889471Sjoerg#endif /* MINIMALISTIC */ 587939214Sgibbs} 588039214Sgibbs 5881214321Smavint 588239214Sgibbsmain(int argc, char **argv) 588339214Sgibbs{ 588439214Sgibbs int c; 588539214Sgibbs char *device = NULL; 588639214Sgibbs int unit = 0; 588739214Sgibbs struct cam_device *cam_dev = NULL; 588839214Sgibbs int timeout = 0, retry_count = 1; 588939214Sgibbs camcontrol_optret optreturn; 589039214Sgibbs char *tstr; 5891118478Sjohan const char *mainopt = "C:En:t:u:v"; 5892118478Sjohan const char *subopt = NULL; 589339214Sgibbs char combinedopt[256]; 589446938Sken int error = 0, optstart = 2; 589546938Sken int devopen = 1; 5896118478Sjohan#ifndef MINIMALISTIC 5897118478Sjohan int bus, target, lun; 5898118478Sjohan#endif /* MINIMALISTIC */ 589939214Sgibbs 5900103092Smdodd cmdlist = CAM_CMD_NONE; 590139214Sgibbs arglist = CAM_ARG_NONE; 590239214Sgibbs 590339214Sgibbs if (argc < 2) { 590446938Sken usage(0); 590539214Sgibbs exit(1); 590639214Sgibbs } 590739214Sgibbs 590839214Sgibbs /* 590939214Sgibbs * Get the base option. 591039214Sgibbs */ 5911216088Sken optreturn = getoption(option_table,argv[1], &cmdlist, &arglist,&subopt); 591239214Sgibbs 591339214Sgibbs if (optreturn == CC_OR_AMBIGUOUS) { 591439214Sgibbs warnx("ambiguous option %s", argv[1]); 591546938Sken usage(0); 591639214Sgibbs exit(1); 591739214Sgibbs } else if (optreturn == CC_OR_NOT_FOUND) { 591839214Sgibbs warnx("option %s not found", argv[1]); 591946938Sken usage(0); 592039214Sgibbs exit(1); 592139214Sgibbs } 592239214Sgibbs 592339214Sgibbs /* 592439214Sgibbs * Ahh, getopt(3) is a pain. 592539214Sgibbs * 592639214Sgibbs * This is a gross hack. There really aren't many other good 592739214Sgibbs * options (excuse the pun) for parsing options in a situation like 592839214Sgibbs * this. getopt is kinda braindead, so you end up having to run 592939214Sgibbs * through the options twice, and give each invocation of getopt 593039214Sgibbs * the option string for the other invocation. 5931214321Smav * 593239214Sgibbs * You would think that you could just have two groups of options. 593339214Sgibbs * The first group would get parsed by the first invocation of 593439214Sgibbs * getopt, and the second group would get parsed by the second 593539214Sgibbs * invocation of getopt. It doesn't quite work out that way. When 593639214Sgibbs * the first invocation of getopt finishes, it leaves optind pointing 593739214Sgibbs * to the argument _after_ the first argument in the second group. 593839214Sgibbs * So when the second invocation of getopt comes around, it doesn't 593939214Sgibbs * recognize the first argument it gets and then bails out. 5940214321Smav * 594139214Sgibbs * A nice alternative would be to have a flag for getopt that says 594239214Sgibbs * "just keep parsing arguments even when you encounter an unknown 594339214Sgibbs * argument", but there isn't one. So there's no real clean way to 594439214Sgibbs * easily parse two sets of arguments without having one invocation 594539214Sgibbs * of getopt know about the other. 5946214321Smav * 594739214Sgibbs * Without this hack, the first invocation of getopt would work as 594839214Sgibbs * long as the generic arguments are first, but the second invocation 594939214Sgibbs * (in the subfunction) would fail in one of two ways. In the case 595039214Sgibbs * where you don't set optreset, it would fail because optind may be 595139214Sgibbs * pointing to the argument after the one it should be pointing at. 595239214Sgibbs * In the case where you do set optreset, and reset optind, it would 595339214Sgibbs * fail because getopt would run into the first set of options, which 595439214Sgibbs * it doesn't understand. 595539214Sgibbs * 595639214Sgibbs * All of this would "sort of" work if you could somehow figure out 595739214Sgibbs * whether optind had been incremented one option too far. The 595839214Sgibbs * mechanics of that, however, are more daunting than just giving 595939214Sgibbs * both invocations all of the expect options for either invocation. 5960214321Smav * 596139214Sgibbs * Needless to say, I wouldn't mind if someone invented a better 596239214Sgibbs * (non-GPL!) command line parsing interface than getopt. I 596339214Sgibbs * wouldn't mind if someone added more knobs to getopt to make it 596439214Sgibbs * work better. Who knows, I may talk myself into doing it someday, 596539214Sgibbs * if the standards weenies let me. As it is, it just leads to 596639214Sgibbs * hackery like this and causes people to avoid it in some cases. 5967214321Smav * 596839214Sgibbs * KDM, September 8th, 1998 596939214Sgibbs */ 597039214Sgibbs if (subopt != NULL) 597139214Sgibbs sprintf(combinedopt, "%s%s", mainopt, subopt); 597239214Sgibbs else 597339214Sgibbs sprintf(combinedopt, "%s", mainopt); 597439214Sgibbs 597539214Sgibbs /* 597646938Sken * For these options we do not parse optional device arguments and 597746938Sken * we do not open a passthrough device. 597839214Sgibbs */ 5979103092Smdodd if ((cmdlist == CAM_CMD_RESCAN) 5980103092Smdodd || (cmdlist == CAM_CMD_RESET) 5981103092Smdodd || (cmdlist == CAM_CMD_DEVTREE) 5982103092Smdodd || (cmdlist == CAM_CMD_USAGE) 5983103092Smdodd || (cmdlist == CAM_CMD_DEBUG)) 598446938Sken devopen = 0; 598539214Sgibbs 598689471Sjoerg#ifndef MINIMALISTIC 598746938Sken if ((devopen == 1) 598846938Sken && (argc > 2 && argv[2][0] != '-')) { 598946938Sken char name[30]; 599046938Sken int rv; 599146938Sken 5992214073Sbrucec if (isdigit(argv[2][0])) { 599346938Sken /* device specified as bus:target[:lun] */ 599446938Sken rv = parse_btl(argv[2], &bus, &target, &lun, &arglist); 599546938Sken if (rv < 2) 599646938Sken errx(1, "numeric device specification must " 599746938Sken "be either bus:target, or " 599846938Sken "bus:target:lun"); 5999126514Sken /* default to 0 if lun was not specified */ 6000126514Sken if ((arglist & CAM_ARG_LUN) == 0) { 6001126514Sken lun = 0; 6002126514Sken arglist |= CAM_ARG_LUN; 6003126514Sken } 600446938Sken optstart++; 600546938Sken } else { 600646938Sken if (cam_get_device(argv[2], name, sizeof name, &unit) 600746938Sken == -1) 600846938Sken errx(1, "%s", cam_errbuf); 600946938Sken device = strdup(name); 601046938Sken arglist |= CAM_ARG_DEVICE | CAM_ARG_UNIT; 601146938Sken optstart++; 601246938Sken } 601346938Sken } 601489471Sjoerg#endif /* MINIMALISTIC */ 601539214Sgibbs /* 601646938Sken * Start getopt processing at argv[2/3], since we've already 601746938Sken * accepted argv[1..2] as the command name, and as a possible 601846938Sken * device name. 601946938Sken */ 602046938Sken optind = optstart; 602146938Sken 602246938Sken /* 602339214Sgibbs * Now we run through the argument list looking for generic 602439214Sgibbs * options, and ignoring options that possibly belong to 602539214Sgibbs * subfunctions. 602639214Sgibbs */ 602739214Sgibbs while ((c = getopt(argc, argv, combinedopt))!= -1){ 602839214Sgibbs switch(c) { 602939214Sgibbs case 'C': 603039214Sgibbs retry_count = strtol(optarg, NULL, 0); 603139214Sgibbs if (retry_count < 0) 603239214Sgibbs errx(1, "retry count %d is < 0", 603339214Sgibbs retry_count); 603439214Sgibbs arglist |= CAM_ARG_RETRIES; 603539214Sgibbs break; 603639214Sgibbs case 'E': 603739214Sgibbs arglist |= CAM_ARG_ERR_RECOVER; 603839214Sgibbs break; 603939214Sgibbs case 'n': 604039214Sgibbs arglist |= CAM_ARG_DEVICE; 604139214Sgibbs tstr = optarg; 604239214Sgibbs while (isspace(*tstr) && (*tstr != '\0')) 604339214Sgibbs tstr++; 604439214Sgibbs device = (char *)strdup(tstr); 604539214Sgibbs break; 604639214Sgibbs case 't': 604739214Sgibbs timeout = strtol(optarg, NULL, 0); 604839214Sgibbs if (timeout < 0) 604939214Sgibbs errx(1, "invalid timeout %d", timeout); 605039214Sgibbs /* Convert the timeout from seconds to ms */ 605139214Sgibbs timeout *= 1000; 605239214Sgibbs arglist |= CAM_ARG_TIMEOUT; 605339214Sgibbs break; 605439214Sgibbs case 'u': 605539214Sgibbs arglist |= CAM_ARG_UNIT; 605639214Sgibbs unit = strtol(optarg, NULL, 0); 605739214Sgibbs break; 605839214Sgibbs case 'v': 605939214Sgibbs arglist |= CAM_ARG_VERBOSE; 606039214Sgibbs break; 606139214Sgibbs default: 606239214Sgibbs break; 606339214Sgibbs } 606439214Sgibbs } 606539214Sgibbs 606689471Sjoerg#ifndef MINIMALISTIC 606739214Sgibbs /* 606839214Sgibbs * For most commands we'll want to open the passthrough device 606939214Sgibbs * associated with the specified device. In the case of the rescan 607039214Sgibbs * commands, we don't use a passthrough device at all, just the 607139214Sgibbs * transport layer device. 607239214Sgibbs */ 607346938Sken if (devopen == 1) { 607461233Sken if (((arglist & (CAM_ARG_BUS|CAM_ARG_TARGET)) == 0) 607561233Sken && (((arglist & CAM_ARG_DEVICE) == 0) 607661233Sken || ((arglist & CAM_ARG_UNIT) == 0))) { 607761233Sken errx(1, "subcommand \"%s\" requires a valid device " 607861233Sken "identifier", argv[1]); 607961233Sken } 608061233Sken 608146938Sken if ((cam_dev = ((arglist & (CAM_ARG_BUS | CAM_ARG_TARGET))? 608246938Sken cam_open_btl(bus, target, lun, O_RDWR, NULL) : 608346938Sken cam_open_spec_device(device,unit,O_RDWR,NULL))) 608446938Sken == NULL) 608539214Sgibbs errx(1,"%s", cam_errbuf); 608639214Sgibbs } 608789471Sjoerg#endif /* MINIMALISTIC */ 608839214Sgibbs 608939214Sgibbs /* 609041112Sken * Reset optind to 2, and reset getopt, so these routines can parse 609139214Sgibbs * the arguments again. 609239214Sgibbs */ 609346938Sken optind = optstart; 609439214Sgibbs optreset = 1; 609539214Sgibbs 6096103092Smdodd switch(cmdlist) { 609789471Sjoerg#ifndef MINIMALISTIC 6098103092Smdodd case CAM_CMD_DEVLIST: 609939214Sgibbs error = getdevlist(cam_dev); 610039214Sgibbs break; 610189521Sjoerg#endif /* MINIMALISTIC */ 6102103092Smdodd case CAM_CMD_DEVTREE: 610339214Sgibbs error = getdevtree(); 610439214Sgibbs break; 610589521Sjoerg#ifndef MINIMALISTIC 6106103092Smdodd case CAM_CMD_TUR: 610746581Sken error = testunitready(cam_dev, retry_count, timeout, 0); 610839214Sgibbs break; 6109103092Smdodd case CAM_CMD_INQUIRY: 611039214Sgibbs error = scsidoinquiry(cam_dev, argc, argv, combinedopt, 611139214Sgibbs retry_count, timeout); 611239214Sgibbs break; 6113195534Sscottl case CAM_CMD_IDENTIFY: 6114195534Sscottl error = ataidentify(cam_dev, retry_count, timeout); 6115195534Sscottl break; 6116103092Smdodd case CAM_CMD_STARTSTOP: 611739214Sgibbs error = scsistart(cam_dev, arglist & CAM_ARG_START_UNIT, 611839214Sgibbs arglist & CAM_ARG_EJECT, retry_count, 611939214Sgibbs timeout); 612039214Sgibbs break; 612189471Sjoerg#endif /* MINIMALISTIC */ 6122103092Smdodd case CAM_CMD_RESCAN: 612341962Smjacob error = dorescan_or_reset(argc, argv, 1); 612439214Sgibbs break; 6125103092Smdodd case CAM_CMD_RESET: 612641962Smjacob error = dorescan_or_reset(argc, argv, 0); 612741962Smjacob break; 612889471Sjoerg#ifndef MINIMALISTIC 6129103092Smdodd case CAM_CMD_READ_DEFECTS: 613039214Sgibbs error = readdefects(cam_dev, argc, argv, combinedopt, 613139214Sgibbs retry_count, timeout); 613239214Sgibbs break; 6133103092Smdodd case CAM_CMD_MODE_PAGE: 613439214Sgibbs modepage(cam_dev, argc, argv, combinedopt, 613539214Sgibbs retry_count, timeout); 613639214Sgibbs break; 6137103092Smdodd case CAM_CMD_SCSI_CMD: 613839214Sgibbs error = scsicmd(cam_dev, argc, argv, combinedopt, 613939214Sgibbs retry_count, timeout); 614039214Sgibbs break; 6141216088Sken case CAM_CMD_SMP_CMD: 6142216088Sken error = smpcmd(cam_dev, argc, argv, combinedopt, 6143216088Sken retry_count, timeout); 6144216088Sken break; 6145216088Sken case CAM_CMD_SMP_RG: 6146216088Sken error = smpreportgeneral(cam_dev, argc, argv, 6147216088Sken combinedopt, retry_count, 6148216088Sken timeout); 6149216088Sken break; 6150216088Sken case CAM_CMD_SMP_PC: 6151216088Sken error = smpphycontrol(cam_dev, argc, argv, combinedopt, 6152216088Sken retry_count, timeout); 6153216088Sken break; 6154216088Sken case CAM_CMD_SMP_PHYLIST: 6155216088Sken error = smpphylist(cam_dev, argc, argv, combinedopt, 6156216088Sken retry_count, timeout); 6157216088Sken break; 6158216088Sken case CAM_CMD_SMP_MANINFO: 6159216088Sken error = smpmaninfo(cam_dev, argc, argv, combinedopt, 6160216088Sken retry_count, timeout); 6161216088Sken break; 6162103092Smdodd case CAM_CMD_DEBUG: 616339214Sgibbs error = camdebug(argc, argv, combinedopt); 616439214Sgibbs break; 6165103092Smdodd case CAM_CMD_TAG: 616646581Sken error = tagcontrol(cam_dev, argc, argv, combinedopt); 616746581Sken break; 6168103092Smdodd case CAM_CMD_RATE: 616946581Sken error = ratecontrol(cam_dev, retry_count, timeout, 617046581Sken argc, argv, combinedopt); 617146581Sken break; 6172103092Smdodd case CAM_CMD_FORMAT: 617360767Sken error = scsiformat(cam_dev, argc, argv, 617460767Sken combinedopt, retry_count, timeout); 617560767Sken break; 6176161506Sken case CAM_CMD_REPORTLUNS: 6177161506Sken error = scsireportluns(cam_dev, argc, argv, 6178161506Sken combinedopt, retry_count, 6179161506Sken timeout); 6180161506Sken break; 6181172093Sken case CAM_CMD_READCAP: 6182172093Sken error = scsireadcapacity(cam_dev, argc, argv, 6183172093Sken combinedopt, retry_count, 6184172093Sken timeout); 6185172093Sken break; 6186199079Smav case CAM_CMD_IDLE: 6187199079Smav case CAM_CMD_STANDBY: 6188199079Smav case CAM_CMD_SLEEP: 6189199079Smav error = atapm(cam_dev, argc, argv, 6190199079Smav combinedopt, retry_count, 6191199079Smav timeout); 6192199079Smav break; 6193227961Semaste case CAM_CMD_DOWNLOAD_FW: 6194227961Semaste error = fwdownload(cam_dev, argc, argv, combinedopt, 6195227961Semaste arglist & CAM_ARG_VERBOSE, retry_count, timeout); 6196227961Semaste break; 619789471Sjoerg#endif /* MINIMALISTIC */ 6198103092Smdodd case CAM_CMD_USAGE: 619946938Sken usage(1); 620046938Sken break; 620139214Sgibbs default: 620246938Sken usage(0); 620339214Sgibbs error = 1; 620439214Sgibbs break; 620539214Sgibbs } 620639214Sgibbs 620739214Sgibbs if (cam_dev != NULL) 620839214Sgibbs cam_close_device(cam_dev); 620939214Sgibbs 621039214Sgibbs exit(error); 621139214Sgibbs} 6212