camcontrol.c revision 260509
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 260509 2014-01-10 12:18:05Z mav $"); 31114513Sobrien 3239214Sgibbs#include <sys/ioctl.h> 33111195Sjohan#include <sys/stdint.h> 3439214Sgibbs#include <sys/types.h> 35255307Sbryanv#include <sys/stat.h> 36195534Sscottl#include <sys/endian.h> 37216088Sken#include <sys/sbuf.h> 38111195Sjohan 3939214Sgibbs#include <stdio.h> 4039214Sgibbs#include <stdlib.h> 4139214Sgibbs#include <string.h> 4239214Sgibbs#include <unistd.h> 43216088Sken#include <inttypes.h> 44216088Sken#include <limits.h> 4539214Sgibbs#include <fcntl.h> 4639214Sgibbs#include <ctype.h> 4739214Sgibbs#include <err.h> 48172093Sken#include <libutil.h> 49249895Ssmh#ifndef MINIMALISTIC 50249895Ssmh#include <limits.h> 51249895Ssmh#include <inttypes.h> 52249895Ssmh#endif 5339214Sgibbs 5439214Sgibbs#include <cam/cam.h> 5539214Sgibbs#include <cam/cam_debug.h> 5639214Sgibbs#include <cam/cam_ccb.h> 5739214Sgibbs#include <cam/scsi/scsi_all.h> 5839214Sgibbs#include <cam/scsi/scsi_da.h> 5939214Sgibbs#include <cam/scsi/scsi_pass.h> 6039214Sgibbs#include <cam/scsi/scsi_message.h> 61216088Sken#include <cam/scsi/smp_all.h> 62195534Sscottl#include <cam/ata/ata_all.h> 6339214Sgibbs#include <camlib.h> 6439214Sgibbs#include "camcontrol.h" 6539214Sgibbs 6639214Sgibbstypedef enum { 67103092Smdodd CAM_CMD_NONE = 0x00000000, 68103092Smdodd CAM_CMD_DEVLIST = 0x00000001, 69103092Smdodd CAM_CMD_TUR = 0x00000002, 70103092Smdodd CAM_CMD_INQUIRY = 0x00000003, 71103092Smdodd CAM_CMD_STARTSTOP = 0x00000004, 72103092Smdodd CAM_CMD_RESCAN = 0x00000005, 73103092Smdodd CAM_CMD_READ_DEFECTS = 0x00000006, 74103092Smdodd CAM_CMD_MODE_PAGE = 0x00000007, 75103092Smdodd CAM_CMD_SCSI_CMD = 0x00000008, 76103092Smdodd CAM_CMD_DEVTREE = 0x00000009, 77103092Smdodd CAM_CMD_USAGE = 0x0000000a, 78103092Smdodd CAM_CMD_DEBUG = 0x0000000b, 79103092Smdodd CAM_CMD_RESET = 0x0000000c, 80103092Smdodd CAM_CMD_FORMAT = 0x0000000d, 81103092Smdodd CAM_CMD_TAG = 0x0000000e, 82103092Smdodd CAM_CMD_RATE = 0x0000000f, 83103092Smdodd CAM_CMD_DETACH = 0x00000010, 84172093Sken CAM_CMD_REPORTLUNS = 0x00000011, 85195534Sscottl CAM_CMD_READCAP = 0x00000012, 86199079Smav CAM_CMD_IDENTIFY = 0x00000013, 87199079Smav CAM_CMD_IDLE = 0x00000014, 88199079Smav CAM_CMD_STANDBY = 0x00000015, 89216088Sken CAM_CMD_SLEEP = 0x00000016, 90216088Sken CAM_CMD_SMP_CMD = 0x00000017, 91216088Sken CAM_CMD_SMP_RG = 0x00000018, 92216088Sken CAM_CMD_SMP_PC = 0x00000019, 93216088Sken CAM_CMD_SMP_PHYLIST = 0x0000001a, 94227961Semaste CAM_CMD_SMP_MANINFO = 0x0000001b, 95249115Ssmh CAM_CMD_DOWNLOAD_FW = 0x0000001c, 96249895Ssmh CAM_CMD_SECURITY = 0x0000001d, 97255307Sbryanv CAM_CMD_HPA = 0x0000001e, 98255307Sbryanv CAM_CMD_SANITIZE = 0x0000001f, 99103092Smdodd} cam_cmdmask; 100103092Smdodd 101103092Smdoddtypedef enum { 10239214Sgibbs CAM_ARG_NONE = 0x00000000, 103103092Smdodd CAM_ARG_VERBOSE = 0x00000001, 104103092Smdodd CAM_ARG_DEVICE = 0x00000002, 105103092Smdodd CAM_ARG_BUS = 0x00000004, 106103092Smdodd CAM_ARG_TARGET = 0x00000008, 107103092Smdodd CAM_ARG_LUN = 0x00000010, 108103092Smdodd CAM_ARG_EJECT = 0x00000020, 109103092Smdodd CAM_ARG_UNIT = 0x00000040, 110103092Smdodd CAM_ARG_FORMAT_BLOCK = 0x00000080, 111103092Smdodd CAM_ARG_FORMAT_BFI = 0x00000100, 112103092Smdodd CAM_ARG_FORMAT_PHYS = 0x00000200, 113103092Smdodd CAM_ARG_PLIST = 0x00000400, 114103092Smdodd CAM_ARG_GLIST = 0x00000800, 115103092Smdodd CAM_ARG_GET_SERIAL = 0x00001000, 116103092Smdodd CAM_ARG_GET_STDINQ = 0x00002000, 117103092Smdodd CAM_ARG_GET_XFERRATE = 0x00004000, 118103092Smdodd CAM_ARG_INQ_MASK = 0x00007000, 119103092Smdodd CAM_ARG_MODE_EDIT = 0x00008000, 120103092Smdodd CAM_ARG_PAGE_CNTL = 0x00010000, 121103092Smdodd CAM_ARG_TIMEOUT = 0x00020000, 122103092Smdodd CAM_ARG_CMD_IN = 0x00040000, 123103092Smdodd CAM_ARG_CMD_OUT = 0x00080000, 124103092Smdodd CAM_ARG_DBD = 0x00100000, 125103092Smdodd CAM_ARG_ERR_RECOVER = 0x00200000, 126103092Smdodd CAM_ARG_RETRIES = 0x00400000, 127103092Smdodd CAM_ARG_START_UNIT = 0x00800000, 128103092Smdodd CAM_ARG_DEBUG_INFO = 0x01000000, 129103092Smdodd CAM_ARG_DEBUG_TRACE = 0x02000000, 130103092Smdodd CAM_ARG_DEBUG_SUBTRACE = 0x04000000, 131103092Smdodd CAM_ARG_DEBUG_CDB = 0x08000000, 132107966Snjl CAM_ARG_DEBUG_XPT = 0x10000000, 133107966Snjl CAM_ARG_DEBUG_PERIPH = 0x20000000, 134236555Smav CAM_ARG_DEBUG_PROBE = 0x40000000, 13539214Sgibbs} cam_argmask; 13639214Sgibbs 13739214Sgibbsstruct camcontrol_opts { 138214321Smav const char *optname; 139216088Sken uint32_t cmdnum; 14039214Sgibbs cam_argmask argnum; 14139214Sgibbs const char *subopt; 14239214Sgibbs}; 14339214Sgibbs 14489471Sjoerg#ifndef MINIMALISTIC 145249895Ssmhstruct ata_res_pass16 { 146249895Ssmh u_int16_t reserved[5]; 147249895Ssmh u_int8_t flags; 148249895Ssmh u_int8_t error; 149249895Ssmh u_int8_t sector_count_exp; 150249895Ssmh u_int8_t sector_count; 151249895Ssmh u_int8_t lba_low_exp; 152249895Ssmh u_int8_t lba_low; 153249895Ssmh u_int8_t lba_mid_exp; 154249895Ssmh u_int8_t lba_mid; 155249895Ssmh u_int8_t lba_high_exp; 156249895Ssmh u_int8_t lba_high; 157249895Ssmh u_int8_t device; 158249895Ssmh u_int8_t status; 159249895Ssmh}; 160249895Ssmh 161249895Ssmhstruct ata_set_max_pwd 162249895Ssmh{ 163249895Ssmh u_int16_t reserved1; 164249895Ssmh u_int8_t password[32]; 165249895Ssmh u_int16_t reserved2[239]; 166249895Ssmh}; 167249895Ssmh 168207498Smavstatic const char scsicmd_opts[] = "a:c:dfi:o:r"; 16939214Sgibbsstatic const char readdefect_opts[] = "f:GP"; 170199821Smavstatic const char negotiate_opts[] = "acD:M:O:qR:T:UW:"; 171216088Skenstatic const char smprg_opts[] = "l"; 172216088Skenstatic const char smppc_opts[] = "a:A:d:lm:M:o:p:s:S:T:"; 173216088Skenstatic const char smpphylist_opts[] = "lq"; 174249115Ssmhstatic char pwd_opt; 17589471Sjoerg#endif 17639214Sgibbs 177227081Sedstatic struct camcontrol_opts option_table[] = { 17889471Sjoerg#ifndef MINIMALISTIC 179103092Smdodd {"tur", CAM_CMD_TUR, CAM_ARG_NONE, NULL}, 180103092Smdodd {"inquiry", CAM_CMD_INQUIRY, CAM_ARG_NONE, "DSR"}, 181195534Sscottl {"identify", CAM_CMD_IDENTIFY, CAM_ARG_NONE, NULL}, 182103092Smdodd {"start", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT, NULL}, 183103092Smdodd {"stop", CAM_CMD_STARTSTOP, CAM_ARG_NONE, NULL}, 184103092Smdodd {"load", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT | CAM_ARG_EJECT, NULL}, 185103092Smdodd {"eject", CAM_CMD_STARTSTOP, CAM_ARG_EJECT, NULL}, 186161506Sken {"reportluns", CAM_CMD_REPORTLUNS, CAM_ARG_NONE, "clr:"}, 187172093Sken {"readcapacity", CAM_CMD_READCAP, CAM_ARG_NONE, "bhHNqs"}, 18889471Sjoerg#endif /* MINIMALISTIC */ 189103092Smdodd {"rescan", CAM_CMD_RESCAN, CAM_ARG_NONE, NULL}, 190103092Smdodd {"reset", CAM_CMD_RESET, CAM_ARG_NONE, NULL}, 19189471Sjoerg#ifndef MINIMALISTIC 192103092Smdodd {"cmd", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts}, 193103092Smdodd {"command", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts}, 194216088Sken {"smpcmd", CAM_CMD_SMP_CMD, CAM_ARG_NONE, "r:R:"}, 195216088Sken {"smprg", CAM_CMD_SMP_RG, CAM_ARG_NONE, smprg_opts}, 196216088Sken {"smpreportgeneral", CAM_CMD_SMP_RG, CAM_ARG_NONE, smprg_opts}, 197216088Sken {"smppc", CAM_CMD_SMP_PC, CAM_ARG_NONE, smppc_opts}, 198216088Sken {"smpphycontrol", CAM_CMD_SMP_PC, CAM_ARG_NONE, smppc_opts}, 199216088Sken {"smpplist", CAM_CMD_SMP_PHYLIST, CAM_ARG_NONE, smpphylist_opts}, 200216088Sken {"smpphylist", CAM_CMD_SMP_PHYLIST, CAM_ARG_NONE, smpphylist_opts}, 201216088Sken {"smpmaninfo", CAM_CMD_SMP_MANINFO, CAM_ARG_NONE, "l"}, 202103092Smdodd {"defects", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts}, 203103092Smdodd {"defectlist", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts}, 20489521Sjoerg#endif /* MINIMALISTIC */ 205260059Sscottl {"devlist", CAM_CMD_DEVTREE, CAM_ARG_NONE, "-b"}, 20689521Sjoerg#ifndef MINIMALISTIC 207103092Smdodd {"periphlist", CAM_CMD_DEVLIST, CAM_ARG_NONE, NULL}, 208103092Smdodd {"modepage", CAM_CMD_MODE_PAGE, CAM_ARG_NONE, "bdelm:P:"}, 209103092Smdodd {"tags", CAM_CMD_TAG, CAM_ARG_NONE, "N:q"}, 210103092Smdodd {"negotiate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts}, 211103092Smdodd {"rate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts}, 212236555Smav {"debug", CAM_CMD_DEBUG, CAM_ARG_NONE, "IPTSXcp"}, 213144134Sken {"format", CAM_CMD_FORMAT, CAM_ARG_NONE, "qrwy"}, 214255307Sbryanv {"sanitize", CAM_CMD_SANITIZE, CAM_ARG_NONE, "a:c:IP:qrUwy"}, 215199079Smav {"idle", CAM_CMD_IDLE, CAM_ARG_NONE, "t:"}, 216199079Smav {"standby", CAM_CMD_STANDBY, CAM_ARG_NONE, "t:"}, 217199079Smav {"sleep", CAM_CMD_SLEEP, CAM_ARG_NONE, ""}, 218227961Semaste {"fwdownload", CAM_CMD_DOWNLOAD_FW, CAM_ARG_NONE, "f:ys"}, 219249115Ssmh {"security", CAM_CMD_SECURITY, CAM_ARG_NONE, "d:e:fh:k:l:qs:T:U:y"}, 220249895Ssmh {"hpa", CAM_CMD_HPA, CAM_ARG_NONE, "Pflp:qs:U:y"}, 22189471Sjoerg#endif /* MINIMALISTIC */ 222103092Smdodd {"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL}, 223103092Smdodd {"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL}, 224103092Smdodd {"-h", CAM_CMD_USAGE, CAM_ARG_NONE, NULL}, 225103092Smdodd {NULL, 0, 0, NULL} 22639214Sgibbs}; 22739214Sgibbs 22839214Sgibbstypedef enum { 22939214Sgibbs CC_OR_NOT_FOUND, 23039214Sgibbs CC_OR_AMBIGUOUS, 23139214Sgibbs CC_OR_FOUND 23239214Sgibbs} camcontrol_optret; 23339214Sgibbs 234216088Skenstruct cam_devitem { 235216088Sken struct device_match_result dev_match; 236216088Sken int num_periphs; 237216088Sken struct periph_match_result *periph_matches; 238216088Sken struct scsi_vpd_device_id *device_id; 239216088Sken int device_id_len; 240216088Sken STAILQ_ENTRY(cam_devitem) links; 241216088Sken}; 242216088Sken 243216088Skenstruct cam_devlist { 244216088Sken STAILQ_HEAD(, cam_devitem) dev_queue; 245216088Sken path_id_t path_id; 246216088Sken}; 247216088Sken 248227081Sedstatic cam_cmdmask cmdlist; 249227081Sedstatic cam_argmask arglist; 25039214Sgibbs 251216088Skencamcontrol_optret getoption(struct camcontrol_opts *table, char *arg, 252216088Sken uint32_t *cmdnum, cam_argmask *argnum, 253118478Sjohan const char **subopt); 25489471Sjoerg#ifndef MINIMALISTIC 25539214Sgibbsstatic int getdevlist(struct cam_device *device); 256126514Sken#endif /* MINIMALISTIC */ 257260059Sscottlstatic int getdevtree(int argc, char **argv, char *combinedopt); 258126514Sken#ifndef MINIMALISTIC 25939214Sgibbsstatic int testunitready(struct cam_device *device, int retry_count, 26046581Sken int timeout, int quiet); 26139214Sgibbsstatic int scsistart(struct cam_device *device, int startstop, int loadeject, 26239214Sgibbs int retry_count, int timeout); 26339214Sgibbsstatic int scsiinquiry(struct cam_device *device, int retry_count, int timeout); 26439214Sgibbsstatic int scsiserial(struct cam_device *device, int retry_count, int timeout); 265198709Smavstatic int camxferrate(struct cam_device *device); 26689471Sjoerg#endif /* MINIMALISTIC */ 267260509Smavstatic int parse_btl(char *tstr, path_id_t *bus, target_id_t *target, 268260509Smav lun_id_t *lun, cam_argmask *arglst); 26941962Smjacobstatic int dorescan_or_reset(int argc, char **argv, int rescan); 270260509Smavstatic int rescan_or_reset_bus(path_id_t bus, int rescan); 271260509Smavstatic int scanlun_or_reset_dev(path_id_t bus, target_id_t target, 272260509Smav lun_id_t lun, int scan); 27389471Sjoerg#ifndef MINIMALISTIC 27439214Sgibbsstatic int readdefects(struct cam_device *device, int argc, char **argv, 27539214Sgibbs char *combinedopt, int retry_count, int timeout); 27639214Sgibbsstatic void modepage(struct cam_device *device, int argc, char **argv, 27739214Sgibbs char *combinedopt, int retry_count, int timeout); 278214321Smavstatic int scsicmd(struct cam_device *device, int argc, char **argv, 27939214Sgibbs char *combinedopt, int retry_count, int timeout); 280216088Skenstatic int smpcmd(struct cam_device *device, int argc, char **argv, 281216088Sken char *combinedopt, int retry_count, int timeout); 282216088Skenstatic int smpreportgeneral(struct cam_device *device, int argc, char **argv, 283216088Sken char *combinedopt, int retry_count, int timeout); 284216088Skenstatic int smpphycontrol(struct cam_device *device, int argc, char **argv, 285216088Sken char *combinedopt, int retry_count, int timeout); 286216088Skenstatic int smpmaninfo(struct cam_device *device, int argc, char **argv, 287216088Sken char *combinedopt, int retry_count, int timeout); 288216088Skenstatic int getdevid(struct cam_devitem *item); 289216088Skenstatic int buildbusdevlist(struct cam_devlist *devlist); 290216088Skenstatic void freebusdevlist(struct cam_devlist *devlist); 291216088Skenstatic struct cam_devitem *findsasdevice(struct cam_devlist *devlist, 292216088Sken uint64_t sasaddr); 293216088Skenstatic int smpphylist(struct cam_device *device, int argc, char **argv, 294216088Sken char *combinedopt, int retry_count, int timeout); 29546581Skenstatic int tagcontrol(struct cam_device *device, int argc, char **argv, 29646581Sken char *combinedopt); 29746581Skenstatic void cts_print(struct cam_device *device, 29846581Sken struct ccb_trans_settings *cts); 29946581Skenstatic void cpi_print(struct ccb_pathinq *cpi); 30046581Skenstatic int get_cpi(struct cam_device *device, struct ccb_pathinq *cpi); 301196658Smavstatic int get_cgd(struct cam_device *device, struct ccb_getdev *cgd); 30246581Skenstatic int get_print_cts(struct cam_device *device, int user_settings, 30346581Sken int quiet, struct ccb_trans_settings *cts); 30446581Skenstatic int ratecontrol(struct cam_device *device, int retry_count, 30546581Sken int timeout, int argc, char **argv, char *combinedopt); 30660767Skenstatic int scsiformat(struct cam_device *device, int argc, char **argv, 30760767Sken char *combinedopt, int retry_count, int timeout); 308255307Sbryanvstatic int scsisanitize(struct cam_device *device, int argc, char **argv, 309255307Sbryanv char *combinedopt, int retry_count, int timeout); 310161506Skenstatic int scsireportluns(struct cam_device *device, int argc, char **argv, 311161506Sken char *combinedopt, int retry_count, int timeout); 312172093Skenstatic int scsireadcapacity(struct cam_device *device, int argc, char **argv, 313172093Sken char *combinedopt, int retry_count, int timeout); 314199079Smavstatic int atapm(struct cam_device *device, int argc, char **argv, 315249115Ssmh char *combinedopt, int retry_count, int timeout); 316249115Ssmhstatic int atasecurity(struct cam_device *device, int retry_count, int timeout, 317249115Ssmh int argc, char **argv, char *combinedopt); 318249895Ssmhstatic int atahpa(struct cam_device *device, int retry_count, int timeout, 319249895Ssmh int argc, char **argv, char *combinedopt); 320249115Ssmh 32189471Sjoerg#endif /* MINIMALISTIC */ 322199747Smav#ifndef min 323199747Smav#define min(a,b) (((a)<(b))?(a):(b)) 324199747Smav#endif 325199747Smav#ifndef max 326199747Smav#define max(a,b) (((a)>(b))?(a):(b)) 327199747Smav#endif 32839214Sgibbs 32939214Sgibbscamcontrol_optret 330216088Skengetoption(struct camcontrol_opts *table, char *arg, uint32_t *cmdnum, 331216088Sken cam_argmask *argnum, const char **subopt) 33239214Sgibbs{ 33339214Sgibbs struct camcontrol_opts *opts; 33439214Sgibbs int num_matches = 0; 33539214Sgibbs 336216088Sken for (opts = table; (opts != NULL) && (opts->optname != NULL); 33739214Sgibbs opts++) { 33839214Sgibbs if (strncmp(opts->optname, arg, strlen(arg)) == 0) { 339103092Smdodd *cmdnum = opts->cmdnum; 34039214Sgibbs *argnum = opts->argnum; 341118478Sjohan *subopt = opts->subopt; 34239214Sgibbs if (++num_matches > 1) 34339214Sgibbs return(CC_OR_AMBIGUOUS); 34439214Sgibbs } 34539214Sgibbs } 34639214Sgibbs 34739214Sgibbs if (num_matches > 0) 34839214Sgibbs return(CC_OR_FOUND); 34939214Sgibbs else 35039214Sgibbs return(CC_OR_NOT_FOUND); 35139214Sgibbs} 35239214Sgibbs 35389471Sjoerg#ifndef MINIMALISTIC 35439214Sgibbsstatic int 35539214Sgibbsgetdevlist(struct cam_device *device) 35639214Sgibbs{ 35739214Sgibbs union ccb *ccb; 35839214Sgibbs char status[32]; 35939214Sgibbs int error = 0; 36039214Sgibbs 36139214Sgibbs ccb = cam_getccb(device); 36239214Sgibbs 36339214Sgibbs ccb->ccb_h.func_code = XPT_GDEVLIST; 36439214Sgibbs ccb->ccb_h.flags = CAM_DIR_NONE; 36539214Sgibbs ccb->ccb_h.retry_count = 1; 36639214Sgibbs ccb->cgdl.index = 0; 36739214Sgibbs ccb->cgdl.status = CAM_GDEVLIST_MORE_DEVS; 36839214Sgibbs while (ccb->cgdl.status == CAM_GDEVLIST_MORE_DEVS) { 36939214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 37039214Sgibbs perror("error getting device list"); 37139214Sgibbs cam_freeccb(ccb); 37239214Sgibbs return(1); 37339214Sgibbs } 37439214Sgibbs 37539214Sgibbs status[0] = '\0'; 37639214Sgibbs 37739214Sgibbs switch (ccb->cgdl.status) { 37839214Sgibbs case CAM_GDEVLIST_MORE_DEVS: 37939214Sgibbs strcpy(status, "MORE"); 38039214Sgibbs break; 38139214Sgibbs case CAM_GDEVLIST_LAST_DEVICE: 38239214Sgibbs strcpy(status, "LAST"); 38339214Sgibbs break; 38439214Sgibbs case CAM_GDEVLIST_LIST_CHANGED: 38539214Sgibbs strcpy(status, "CHANGED"); 38639214Sgibbs break; 38739214Sgibbs case CAM_GDEVLIST_ERROR: 38839214Sgibbs strcpy(status, "ERROR"); 38939214Sgibbs error = 1; 39039214Sgibbs break; 39139214Sgibbs } 39239214Sgibbs 39339214Sgibbs fprintf(stdout, "%s%d: generation: %d index: %d status: %s\n", 39439214Sgibbs ccb->cgdl.periph_name, 39539214Sgibbs ccb->cgdl.unit_number, 39639214Sgibbs ccb->cgdl.generation, 39739214Sgibbs ccb->cgdl.index, 39839214Sgibbs status); 39939214Sgibbs 40039214Sgibbs /* 40139214Sgibbs * If the list has changed, we need to start over from the 40239214Sgibbs * beginning. 40339214Sgibbs */ 40439214Sgibbs if (ccb->cgdl.status == CAM_GDEVLIST_LIST_CHANGED) 40539214Sgibbs ccb->cgdl.index = 0; 40639214Sgibbs } 40739214Sgibbs 40839214Sgibbs cam_freeccb(ccb); 40939214Sgibbs 41039214Sgibbs return(error); 41139214Sgibbs} 41289521Sjoerg#endif /* MINIMALISTIC */ 41339214Sgibbs 41439214Sgibbsstatic int 415260059Sscottlgetdevtree(int argc, char **argv, char *combinedopt) 41639214Sgibbs{ 41739214Sgibbs union ccb ccb; 418102192Sjohan int bufsize, fd; 419102192Sjohan unsigned int i; 42039214Sgibbs int need_close = 0; 42139214Sgibbs int error = 0; 42246581Sken int skip_device = 0; 423260059Sscottl int busonly = 0; 424260087Sscottl int c; 42539214Sgibbs 426260059Sscottl while ((c = getopt(argc, argv, combinedopt)) != -1) { 427260059Sscottl switch(c) { 428260059Sscottl case 'b': 429260059Sscottl if ((arglist & CAM_ARG_VERBOSE) == 0) 430260059Sscottl busonly = 1; 431260059Sscottl break; 432260059Sscottl default: 433260059Sscottl break; 434260059Sscottl } 435260059Sscottl } 436260059Sscottl 43739214Sgibbs if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) { 43839214Sgibbs warn("couldn't open %s", XPT_DEVICE); 43939214Sgibbs return(1); 44039214Sgibbs } 44139214Sgibbs 442126514Sken bzero(&ccb, sizeof(union ccb)); 44339214Sgibbs 444126514Sken ccb.ccb_h.path_id = CAM_XPT_PATH_ID; 445126514Sken ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; 446126514Sken ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; 447126514Sken 44839214Sgibbs ccb.ccb_h.func_code = XPT_DEV_MATCH; 44939214Sgibbs bufsize = sizeof(struct dev_match_result) * 100; 45039214Sgibbs ccb.cdm.match_buf_len = bufsize; 45139214Sgibbs ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize); 45269471Sjedgar if (ccb.cdm.matches == NULL) { 45369471Sjedgar warnx("can't malloc memory for matches"); 45469471Sjedgar close(fd); 45569471Sjedgar return(1); 45669471Sjedgar } 45739214Sgibbs ccb.cdm.num_matches = 0; 45839214Sgibbs 45939214Sgibbs /* 46039214Sgibbs * We fetch all nodes, since we display most of them in the default 46139214Sgibbs * case, and all in the verbose case. 46239214Sgibbs */ 46339214Sgibbs ccb.cdm.num_patterns = 0; 46439214Sgibbs ccb.cdm.pattern_buf_len = 0; 46539214Sgibbs 46639214Sgibbs /* 46739214Sgibbs * We do the ioctl multiple times if necessary, in case there are 46839214Sgibbs * more than 100 nodes in the EDT. 46939214Sgibbs */ 47039214Sgibbs do { 47139214Sgibbs if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 47239214Sgibbs warn("error sending CAMIOCOMMAND ioctl"); 47339214Sgibbs error = 1; 47439214Sgibbs break; 47539214Sgibbs } 47639214Sgibbs 47739214Sgibbs if ((ccb.ccb_h.status != CAM_REQ_CMP) 47839214Sgibbs || ((ccb.cdm.status != CAM_DEV_MATCH_LAST) 47939214Sgibbs && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { 48089515Sken warnx("got CAM error %#x, CDM error %d\n", 48189515Sken ccb.ccb_h.status, ccb.cdm.status); 48239214Sgibbs error = 1; 48339214Sgibbs break; 48439214Sgibbs } 48539214Sgibbs 48639214Sgibbs for (i = 0; i < ccb.cdm.num_matches; i++) { 48789515Sken switch (ccb.cdm.matches[i].type) { 48839214Sgibbs case DEV_MATCH_BUS: { 48939214Sgibbs struct bus_match_result *bus_result; 49039214Sgibbs 49139214Sgibbs /* 49239214Sgibbs * Only print the bus information if the 49339214Sgibbs * user turns on the verbose flag. 49439214Sgibbs */ 495260059Sscottl if ((busonly == 0) && 496260059Sscottl (arglist & CAM_ARG_VERBOSE) == 0) 49739214Sgibbs break; 49839214Sgibbs 49939214Sgibbs bus_result = 50039214Sgibbs &ccb.cdm.matches[i].result.bus_result; 50139214Sgibbs 50239214Sgibbs if (need_close) { 50339214Sgibbs fprintf(stdout, ")\n"); 50439214Sgibbs need_close = 0; 50539214Sgibbs } 50639214Sgibbs 507260059Sscottl fprintf(stdout, "scbus%d on %s%d bus %d%s\n", 50839214Sgibbs bus_result->path_id, 50939214Sgibbs bus_result->dev_name, 51039214Sgibbs bus_result->unit_number, 511260059Sscottl bus_result->bus_id, 512260059Sscottl (busonly ? "" : ":")); 51339214Sgibbs break; 51439214Sgibbs } 51539214Sgibbs case DEV_MATCH_DEVICE: { 51639214Sgibbs struct device_match_result *dev_result; 51739214Sgibbs char vendor[16], product[48], revision[16]; 518235897Smav char fw[5], tmpstr[256]; 51939214Sgibbs 520260059Sscottl if (busonly == 1) 521260059Sscottl break; 522260059Sscottl 52339214Sgibbs dev_result = 52439214Sgibbs &ccb.cdm.matches[i].result.device_result; 52539214Sgibbs 52646581Sken if ((dev_result->flags 52746581Sken & DEV_RESULT_UNCONFIGURED) 52846581Sken && ((arglist & CAM_ARG_VERBOSE) == 0)) { 52946581Sken skip_device = 1; 53046581Sken break; 53146581Sken } else 53246581Sken skip_device = 0; 53346581Sken 534195534Sscottl if (dev_result->protocol == PROTO_SCSI) { 535195534Sscottl cam_strvis(vendor, dev_result->inq_data.vendor, 53639214Sgibbs sizeof(dev_result->inq_data.vendor), 53739214Sgibbs sizeof(vendor)); 538195534Sscottl cam_strvis(product, 53939214Sgibbs dev_result->inq_data.product, 54039214Sgibbs sizeof(dev_result->inq_data.product), 54139214Sgibbs sizeof(product)); 542195534Sscottl cam_strvis(revision, 54339214Sgibbs dev_result->inq_data.revision, 54439214Sgibbs sizeof(dev_result->inq_data.revision), 54539214Sgibbs sizeof(revision)); 546195534Sscottl sprintf(tmpstr, "<%s %s %s>", vendor, product, 54739214Sgibbs revision); 548195534Sscottl } else if (dev_result->protocol == PROTO_ATA || 549195534Sscottl dev_result->protocol == PROTO_SATAPM) { 550195534Sscottl cam_strvis(product, 551195534Sscottl dev_result->ident_data.model, 552195534Sscottl sizeof(dev_result->ident_data.model), 553195534Sscottl sizeof(product)); 554195534Sscottl cam_strvis(revision, 555195534Sscottl dev_result->ident_data.revision, 556195534Sscottl sizeof(dev_result->ident_data.revision), 557195534Sscottl sizeof(revision)); 558195534Sscottl sprintf(tmpstr, "<%s %s>", product, 559195534Sscottl revision); 560235897Smav } else if (dev_result->protocol == PROTO_SEMB) { 561235897Smav struct sep_identify_data *sid; 562235897Smav 563235897Smav sid = (struct sep_identify_data *) 564235897Smav &dev_result->ident_data; 565235897Smav cam_strvis(vendor, sid->vendor_id, 566235897Smav sizeof(sid->vendor_id), 567235897Smav sizeof(vendor)); 568235897Smav cam_strvis(product, sid->product_id, 569235897Smav sizeof(sid->product_id), 570235897Smav sizeof(product)); 571235897Smav cam_strvis(revision, sid->product_rev, 572235897Smav sizeof(sid->product_rev), 573235897Smav sizeof(revision)); 574235897Smav cam_strvis(fw, sid->firmware_rev, 575235897Smav sizeof(sid->firmware_rev), 576235897Smav sizeof(fw)); 577235897Smav sprintf(tmpstr, "<%s %s %s %s>", 578235897Smav vendor, product, revision, fw); 579195534Sscottl } else { 580195534Sscottl sprintf(tmpstr, "<>"); 581195534Sscottl } 58239214Sgibbs if (need_close) { 58339214Sgibbs fprintf(stdout, ")\n"); 58439214Sgibbs need_close = 0; 58539214Sgibbs } 58639214Sgibbs 58739214Sgibbs fprintf(stdout, "%-33s at scbus%d " 588257382Snwhitehorn "target %d lun %jx (", 58939214Sgibbs tmpstr, 59039214Sgibbs dev_result->path_id, 59139214Sgibbs dev_result->target_id, 592257382Snwhitehorn (uintmax_t)dev_result->target_lun); 59342647Sgibbs 59442647Sgibbs need_close = 1; 59542647Sgibbs 59639214Sgibbs break; 59739214Sgibbs } 59839214Sgibbs case DEV_MATCH_PERIPH: { 59939214Sgibbs struct periph_match_result *periph_result; 60039214Sgibbs 60139214Sgibbs periph_result = 60239214Sgibbs &ccb.cdm.matches[i].result.periph_result; 60339214Sgibbs 604260059Sscottl if (busonly || skip_device != 0) 60546581Sken break; 60646581Sken 60742647Sgibbs if (need_close > 1) 60839214Sgibbs fprintf(stdout, ","); 60939214Sgibbs 61039214Sgibbs fprintf(stdout, "%s%d", 61139214Sgibbs periph_result->periph_name, 61239214Sgibbs periph_result->unit_number); 61339214Sgibbs 61442647Sgibbs need_close++; 61539214Sgibbs break; 61639214Sgibbs } 61739214Sgibbs default: 61839214Sgibbs fprintf(stdout, "unknown match type\n"); 61939214Sgibbs break; 62039214Sgibbs } 62139214Sgibbs } 62239214Sgibbs 62339214Sgibbs } while ((ccb.ccb_h.status == CAM_REQ_CMP) 62439214Sgibbs && (ccb.cdm.status == CAM_DEV_MATCH_MORE)); 62539214Sgibbs 62639214Sgibbs if (need_close) 62739214Sgibbs fprintf(stdout, ")\n"); 62839214Sgibbs 62939214Sgibbs close(fd); 63039214Sgibbs 63139214Sgibbs return(error); 63239214Sgibbs} 63339214Sgibbs 63489521Sjoerg#ifndef MINIMALISTIC 63539214Sgibbsstatic int 63646581Skentestunitready(struct cam_device *device, int retry_count, int timeout, 63746581Sken int quiet) 63839214Sgibbs{ 63939214Sgibbs int error = 0; 64039214Sgibbs union ccb *ccb; 64139214Sgibbs 64239214Sgibbs ccb = cam_getccb(device); 64339214Sgibbs 64439214Sgibbs scsi_test_unit_ready(&ccb->csio, 64539214Sgibbs /* retries */ retry_count, 64639214Sgibbs /* cbfcnp */ NULL, 64739214Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 64839214Sgibbs /* sense_len */ SSD_FULL_SIZE, 64939214Sgibbs /* timeout */ timeout ? timeout : 5000); 65039214Sgibbs 65139214Sgibbs /* Disable freezing the device queue */ 65239214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 65339214Sgibbs 65439214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 65539214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 65639214Sgibbs 65739214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 65846581Sken if (quiet == 0) 65946581Sken perror("error sending test unit ready"); 66039214Sgibbs 66139214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 66274840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 66374840Sken CAM_EPF_ALL, stderr); 66439214Sgibbs } 66539214Sgibbs 66639214Sgibbs cam_freeccb(ccb); 66739214Sgibbs return(1); 66839214Sgibbs } 66939214Sgibbs 67046581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 67146581Sken if (quiet == 0) 67246581Sken fprintf(stdout, "Unit is ready\n"); 67346581Sken } else { 67446581Sken if (quiet == 0) 67546581Sken fprintf(stdout, "Unit is not ready\n"); 67639214Sgibbs error = 1; 67739214Sgibbs 67839214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 67974840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 68074840Sken CAM_EPF_ALL, stderr); 68139214Sgibbs } 68239214Sgibbs } 68339214Sgibbs 68439214Sgibbs cam_freeccb(ccb); 68539214Sgibbs 68639214Sgibbs return(error); 68739214Sgibbs} 68839214Sgibbs 68939214Sgibbsstatic int 69039214Sgibbsscsistart(struct cam_device *device, int startstop, int loadeject, 69139214Sgibbs int retry_count, int timeout) 69239214Sgibbs{ 69339214Sgibbs union ccb *ccb; 69439214Sgibbs int error = 0; 69539214Sgibbs 69639214Sgibbs ccb = cam_getccb(device); 69739214Sgibbs 69840319Sken /* 69940319Sken * If we're stopping, send an ordered tag so the drive in question 70040319Sken * will finish any previously queued writes before stopping. If 70140319Sken * the device isn't capable of tagged queueing, or if tagged 70240319Sken * queueing is turned off, the tag action is a no-op. 70340319Sken */ 70439214Sgibbs scsi_start_stop(&ccb->csio, 70539214Sgibbs /* retries */ retry_count, 70639214Sgibbs /* cbfcnp */ NULL, 70740319Sken /* tag_action */ startstop ? MSG_SIMPLE_Q_TAG : 70840319Sken MSG_ORDERED_Q_TAG, 70939214Sgibbs /* start/stop */ startstop, 71039214Sgibbs /* load_eject */ loadeject, 71139214Sgibbs /* immediate */ 0, 71239214Sgibbs /* sense_len */ SSD_FULL_SIZE, 71339214Sgibbs /* timeout */ timeout ? timeout : 120000); 71439214Sgibbs 71539214Sgibbs /* Disable freezing the device queue */ 71639214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 71739214Sgibbs 71839214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 71939214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 72039214Sgibbs 72139214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 72239214Sgibbs perror("error sending start unit"); 72339214Sgibbs 72439214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 72574840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 72674840Sken CAM_EPF_ALL, stderr); 72739214Sgibbs } 72839214Sgibbs 72939214Sgibbs cam_freeccb(ccb); 73039214Sgibbs return(1); 73139214Sgibbs } 73239214Sgibbs 73339214Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 73439214Sgibbs if (startstop) { 73539214Sgibbs fprintf(stdout, "Unit started successfully"); 73639214Sgibbs if (loadeject) 73739214Sgibbs fprintf(stdout,", Media loaded\n"); 73839214Sgibbs else 73939214Sgibbs fprintf(stdout,"\n"); 74039214Sgibbs } else { 74139214Sgibbs fprintf(stdout, "Unit stopped successfully"); 74239214Sgibbs if (loadeject) 74339214Sgibbs fprintf(stdout, ", Media ejected\n"); 74439214Sgibbs else 74539214Sgibbs fprintf(stdout, "\n"); 74639214Sgibbs } 74739214Sgibbs else { 74839214Sgibbs error = 1; 74939214Sgibbs if (startstop) 75039214Sgibbs fprintf(stdout, 75139214Sgibbs "Error received from start unit command\n"); 75239214Sgibbs else 75339214Sgibbs fprintf(stdout, 75439214Sgibbs "Error received from stop unit command\n"); 755214321Smav 75639214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 75774840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 75874840Sken CAM_EPF_ALL, stderr); 75939214Sgibbs } 76039214Sgibbs } 76139214Sgibbs 76239214Sgibbs cam_freeccb(ccb); 76339214Sgibbs 76439214Sgibbs return(error); 76539214Sgibbs} 76639214Sgibbs 767227961Semasteint 76839214Sgibbsscsidoinquiry(struct cam_device *device, int argc, char **argv, 76939214Sgibbs char *combinedopt, int retry_count, int timeout) 77039214Sgibbs{ 77139214Sgibbs int c; 77239214Sgibbs int error = 0; 77339214Sgibbs 77439214Sgibbs while ((c = getopt(argc, argv, combinedopt)) != -1) { 77539214Sgibbs switch(c) { 77639214Sgibbs case 'D': 77739214Sgibbs arglist |= CAM_ARG_GET_STDINQ; 77839214Sgibbs break; 77939214Sgibbs case 'R': 78039214Sgibbs arglist |= CAM_ARG_GET_XFERRATE; 78139214Sgibbs break; 78239214Sgibbs case 'S': 78339214Sgibbs arglist |= CAM_ARG_GET_SERIAL; 78439214Sgibbs break; 78539214Sgibbs default: 78639214Sgibbs break; 78739214Sgibbs } 78839214Sgibbs } 78939214Sgibbs 79039214Sgibbs /* 79139214Sgibbs * If the user didn't specify any inquiry options, he wants all of 79239214Sgibbs * them. 79339214Sgibbs */ 79439214Sgibbs if ((arglist & CAM_ARG_INQ_MASK) == 0) 79539214Sgibbs arglist |= CAM_ARG_INQ_MASK; 79639214Sgibbs 79739214Sgibbs if (arglist & CAM_ARG_GET_STDINQ) 79839214Sgibbs error = scsiinquiry(device, retry_count, timeout); 79939214Sgibbs 80039214Sgibbs if (error != 0) 80139214Sgibbs return(error); 80239214Sgibbs 80339214Sgibbs if (arglist & CAM_ARG_GET_SERIAL) 80439214Sgibbs scsiserial(device, retry_count, timeout); 80539214Sgibbs 80639214Sgibbs if (error != 0) 80739214Sgibbs return(error); 80839214Sgibbs 80939214Sgibbs if (arglist & CAM_ARG_GET_XFERRATE) 810198709Smav error = camxferrate(device); 81139214Sgibbs 81239214Sgibbs return(error); 81339214Sgibbs} 81439214Sgibbs 81539214Sgibbsstatic int 81639214Sgibbsscsiinquiry(struct cam_device *device, int retry_count, int timeout) 81739214Sgibbs{ 81839214Sgibbs union ccb *ccb; 81939214Sgibbs struct scsi_inquiry_data *inq_buf; 82039214Sgibbs int error = 0; 821214321Smav 82239214Sgibbs ccb = cam_getccb(device); 82339214Sgibbs 82439214Sgibbs if (ccb == NULL) { 82539214Sgibbs warnx("couldn't allocate CCB"); 82639214Sgibbs return(1); 82739214Sgibbs } 82839214Sgibbs 82939214Sgibbs /* cam_getccb cleans up the header, caller has to zero the payload */ 83046581Sken bzero(&(&ccb->ccb_h)[1], 83146581Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 83239214Sgibbs 83339214Sgibbs inq_buf = (struct scsi_inquiry_data *)malloc( 83439214Sgibbs sizeof(struct scsi_inquiry_data)); 83539214Sgibbs 83639214Sgibbs if (inq_buf == NULL) { 83739214Sgibbs cam_freeccb(ccb); 83839214Sgibbs warnx("can't malloc memory for inquiry\n"); 83939214Sgibbs return(1); 84039214Sgibbs } 84139214Sgibbs bzero(inq_buf, sizeof(*inq_buf)); 84239214Sgibbs 84357349Sken /* 84457349Sken * Note that although the size of the inquiry buffer is the full 84557349Sken * 256 bytes specified in the SCSI spec, we only tell the device 84657349Sken * that we have allocated SHORT_INQUIRY_LENGTH bytes. There are 84757349Sken * two reasons for this: 84857349Sken * 84957349Sken * - The SCSI spec says that when a length field is only 1 byte, 85057349Sken * a value of 0 will be interpreted as 256. Therefore 85157349Sken * scsi_inquiry() will convert an inq_len (which is passed in as 85257349Sken * a u_int32_t, but the field in the CDB is only 1 byte) of 256 85357349Sken * to 0. Evidently, very few devices meet the spec in that 854214321Smav * regard. Some devices, like many Seagate disks, take the 0 as 85557349Sken * 0, and don't return any data. One Pioneer DVD-R drive 85657349Sken * returns more data than the command asked for. 85757349Sken * 85857349Sken * So, since there are numerous devices that just don't work 85957349Sken * right with the full inquiry size, we don't send the full size. 860214321Smav * 86157349Sken * - The second reason not to use the full inquiry data length is 86257349Sken * that we don't need it here. The only reason we issue a 86357349Sken * standard inquiry is to get the vendor name, device name, 86457349Sken * and revision so scsi_print_inquiry() can print them. 86557349Sken * 86657349Sken * If, at some point in the future, more inquiry data is needed for 86757349Sken * some reason, this code should use a procedure similar to the 86857349Sken * probe code. i.e., issue a short inquiry, and determine from 86957349Sken * the additional length passed back from the device how much 87057349Sken * inquiry data the device supports. Once the amount the device 87157349Sken * supports is determined, issue an inquiry for that amount and no 87257349Sken * more. 87357349Sken * 87457349Sken * KDM, 2/18/2000 87557349Sken */ 87639214Sgibbs scsi_inquiry(&ccb->csio, 87739214Sgibbs /* retries */ retry_count, 87839214Sgibbs /* cbfcnp */ NULL, 87939214Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 88039214Sgibbs /* inq_buf */ (u_int8_t *)inq_buf, 88157349Sken /* inq_len */ SHORT_INQUIRY_LENGTH, 88239214Sgibbs /* evpd */ 0, 88339214Sgibbs /* page_code */ 0, 88439214Sgibbs /* sense_len */ SSD_FULL_SIZE, 88539214Sgibbs /* timeout */ timeout ? timeout : 5000); 88639214Sgibbs 88739214Sgibbs /* Disable freezing the device queue */ 88839214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 88939214Sgibbs 89039214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 89139214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 89239214Sgibbs 89339214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 89439214Sgibbs perror("error sending SCSI inquiry"); 89539214Sgibbs 89639214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 89774840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 89874840Sken CAM_EPF_ALL, stderr); 89939214Sgibbs } 90039214Sgibbs 90139214Sgibbs cam_freeccb(ccb); 90239214Sgibbs return(1); 90339214Sgibbs } 90439214Sgibbs 90539214Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 90639214Sgibbs error = 1; 90739214Sgibbs 90839214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 90974840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 91074840Sken CAM_EPF_ALL, stderr); 91139214Sgibbs } 91239214Sgibbs } 91339214Sgibbs 91439214Sgibbs cam_freeccb(ccb); 91539214Sgibbs 91639214Sgibbs if (error != 0) { 91739214Sgibbs free(inq_buf); 91839214Sgibbs return(error); 91939214Sgibbs } 92039214Sgibbs 92146581Sken fprintf(stdout, "%s%d: ", device->device_name, 92246581Sken device->dev_unit_num); 92339214Sgibbs scsi_print_inquiry(inq_buf); 92439214Sgibbs 92539214Sgibbs free(inq_buf); 92639214Sgibbs 92739214Sgibbs return(0); 92839214Sgibbs} 92939214Sgibbs 93039214Sgibbsstatic int 93139214Sgibbsscsiserial(struct cam_device *device, int retry_count, int timeout) 93239214Sgibbs{ 93339214Sgibbs union ccb *ccb; 93439214Sgibbs struct scsi_vpd_unit_serial_number *serial_buf; 93539214Sgibbs char serial_num[SVPD_SERIAL_NUM_SIZE + 1]; 93639214Sgibbs int error = 0; 93739214Sgibbs 93839214Sgibbs ccb = cam_getccb(device); 93939214Sgibbs 94039214Sgibbs if (ccb == NULL) { 94139214Sgibbs warnx("couldn't allocate CCB"); 94239214Sgibbs return(1); 94339214Sgibbs } 94439214Sgibbs 94539214Sgibbs /* cam_getccb cleans up the header, caller has to zero the payload */ 94646581Sken bzero(&(&ccb->ccb_h)[1], 94746581Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 94839214Sgibbs 94939214Sgibbs serial_buf = (struct scsi_vpd_unit_serial_number *) 95039214Sgibbs malloc(sizeof(*serial_buf)); 95139214Sgibbs 95239214Sgibbs if (serial_buf == NULL) { 95339214Sgibbs cam_freeccb(ccb); 95439214Sgibbs warnx("can't malloc memory for serial number"); 95539214Sgibbs return(1); 95639214Sgibbs } 95739214Sgibbs 95839214Sgibbs scsi_inquiry(&ccb->csio, 95939214Sgibbs /*retries*/ retry_count, 96039214Sgibbs /*cbfcnp*/ NULL, 96139214Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 96239214Sgibbs /* inq_buf */ (u_int8_t *)serial_buf, 96339214Sgibbs /* inq_len */ sizeof(*serial_buf), 96439214Sgibbs /* evpd */ 1, 96539214Sgibbs /* page_code */ SVPD_UNIT_SERIAL_NUMBER, 96639214Sgibbs /* sense_len */ SSD_FULL_SIZE, 96739214Sgibbs /* timeout */ timeout ? timeout : 5000); 96839214Sgibbs 96939214Sgibbs /* Disable freezing the device queue */ 97039214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 97139214Sgibbs 97239214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 97339214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 97439214Sgibbs 97539214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 97639214Sgibbs warn("error getting serial number"); 97739214Sgibbs 97839214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 97974840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 98074840Sken CAM_EPF_ALL, stderr); 98139214Sgibbs } 98239214Sgibbs 98339214Sgibbs cam_freeccb(ccb); 98439214Sgibbs free(serial_buf); 98539214Sgibbs return(1); 98639214Sgibbs } 98739214Sgibbs 98839214Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 98939214Sgibbs error = 1; 99039214Sgibbs 99139214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 99274840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 99374840Sken CAM_EPF_ALL, stderr); 99439214Sgibbs } 99539214Sgibbs } 99639214Sgibbs 99739214Sgibbs cam_freeccb(ccb); 99839214Sgibbs 99939214Sgibbs if (error != 0) { 100039214Sgibbs free(serial_buf); 100139214Sgibbs return(error); 100239214Sgibbs } 100339214Sgibbs 100439214Sgibbs bcopy(serial_buf->serial_num, serial_num, serial_buf->length); 100539214Sgibbs serial_num[serial_buf->length] = '\0'; 100639214Sgibbs 100746581Sken if ((arglist & CAM_ARG_GET_STDINQ) 100846581Sken || (arglist & CAM_ARG_GET_XFERRATE)) 100946581Sken fprintf(stdout, "%s%d: Serial Number ", 101046581Sken device->device_name, device->dev_unit_num); 101139214Sgibbs 101239214Sgibbs fprintf(stdout, "%.60s\n", serial_num); 101339214Sgibbs 101439214Sgibbs free(serial_buf); 101539214Sgibbs 101639214Sgibbs return(0); 101739214Sgibbs} 101839214Sgibbs 101939214Sgibbsstatic int 1020198709Smavcamxferrate(struct cam_device *device) 102139214Sgibbs{ 1022198709Smav struct ccb_pathinq cpi; 1023163896Smjacob u_int32_t freq = 0; 1024163896Smjacob u_int32_t speed = 0; 102546581Sken union ccb *ccb; 102646581Sken u_int mb; 102746581Sken int retval = 0; 102839214Sgibbs 1029198709Smav if ((retval = get_cpi(device, &cpi)) != 0) 1030198709Smav return (1); 1031198709Smav 103246581Sken ccb = cam_getccb(device); 103346581Sken 103446581Sken if (ccb == NULL) { 103546581Sken warnx("couldn't allocate CCB"); 103646581Sken return(1); 103746581Sken } 103846581Sken 103946581Sken bzero(&(&ccb->ccb_h)[1], 104046581Sken sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr)); 104146581Sken 104246581Sken ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 1043163896Smjacob ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS; 104446581Sken 104546581Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 104646581Sken || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 104769254Skris const char error_string[] = "error getting transfer settings"; 104846581Sken 104946581Sken if (retval < 0) 105046581Sken warn(error_string); 105146581Sken else 105246581Sken warnx(error_string); 105346581Sken 105446581Sken if (arglist & CAM_ARG_VERBOSE) 105574840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 105674840Sken CAM_EPF_ALL, stderr); 105746581Sken 105846581Sken retval = 1; 105946581Sken 106046581Sken goto xferrate_bailout; 106146581Sken 106246581Sken } 106346581Sken 1064198709Smav speed = cpi.base_transfer_speed; 1065198709Smav freq = 0; 1066163896Smjacob if (ccb->cts.transport == XPORT_SPI) { 1067163896Smjacob struct ccb_trans_settings_spi *spi = 1068163896Smjacob &ccb->cts.xport_specific.spi; 1069163896Smjacob 1070163896Smjacob if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) { 1071163896Smjacob freq = scsi_calc_syncsrate(spi->sync_period); 1072163896Smjacob speed = freq; 1073163896Smjacob } 1074163896Smjacob if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 1075163896Smjacob speed *= (0x01 << spi->bus_width); 1076163896Smjacob } 1077198709Smav } else if (ccb->cts.transport == XPORT_FC) { 1078198709Smav struct ccb_trans_settings_fc *fc = 1079198709Smav &ccb->cts.xport_specific.fc; 1080163896Smjacob 1081198709Smav if (fc->valid & CTS_FC_VALID_SPEED) 1082198709Smav speed = fc->bitrate; 1083198709Smav } else if (ccb->cts.transport == XPORT_SAS) { 1084198709Smav struct ccb_trans_settings_sas *sas = 1085198709Smav &ccb->cts.xport_specific.sas; 1086163896Smjacob 1087198709Smav if (sas->valid & CTS_SAS_VALID_SPEED) 1088198709Smav speed = sas->bitrate; 1089199747Smav } else if (ccb->cts.transport == XPORT_ATA) { 1090236437Smav struct ccb_trans_settings_pata *pata = 1091199747Smav &ccb->cts.xport_specific.ata; 1092199747Smav 1093236437Smav if (pata->valid & CTS_ATA_VALID_MODE) 1094236437Smav speed = ata_mode2speed(pata->mode); 1095198709Smav } else if (ccb->cts.transport == XPORT_SATA) { 1096199747Smav struct ccb_trans_settings_sata *sata = 1097198709Smav &ccb->cts.xport_specific.sata; 1098163896Smjacob 1099199747Smav if (sata->valid & CTS_SATA_VALID_REVISION) 1100199747Smav speed = ata_revision2speed(sata->revision); 1101198709Smav } 1102198709Smav 1103198709Smav mb = speed / 1000; 1104198709Smav if (mb > 0) { 1105199747Smav fprintf(stdout, "%s%d: %d.%03dMB/s transfers", 1106198709Smav device->device_name, device->dev_unit_num, 1107198709Smav mb, speed % 1000); 1108198709Smav } else { 1109199747Smav fprintf(stdout, "%s%d: %dKB/s transfers", 1110198709Smav device->device_name, device->dev_unit_num, 1111198709Smav speed); 1112198709Smav } 1113198709Smav 1114198709Smav if (ccb->cts.transport == XPORT_SPI) { 1115198709Smav struct ccb_trans_settings_spi *spi = 1116198709Smav &ccb->cts.xport_specific.spi; 1117198709Smav 1118163896Smjacob if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0) 1119163896Smjacob && (spi->sync_offset != 0)) 1120199747Smav fprintf(stdout, " (%d.%03dMHz, offset %d", freq / 1000, 1121163896Smjacob freq % 1000, spi->sync_offset); 1122163896Smjacob 1123163896Smjacob if (((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) 1124163896Smjacob && (spi->bus_width > 0)) { 1125163896Smjacob if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0) 1126163896Smjacob && (spi->sync_offset != 0)) { 1127163896Smjacob fprintf(stdout, ", "); 1128163896Smjacob } else { 1129163896Smjacob fprintf(stdout, " ("); 1130163896Smjacob } 1131163896Smjacob fprintf(stdout, "%dbit)", 8 * (0x01 << spi->bus_width)); 1132163896Smjacob } else if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0) 1133163896Smjacob && (spi->sync_offset != 0)) { 1134163896Smjacob fprintf(stdout, ")"); 1135163896Smjacob } 1136198709Smav } else if (ccb->cts.transport == XPORT_ATA) { 1137236437Smav struct ccb_trans_settings_pata *pata = 1138198709Smav &ccb->cts.xport_specific.ata; 113946581Sken 1140199747Smav printf(" ("); 1141236437Smav if (pata->valid & CTS_ATA_VALID_MODE) 1142236437Smav printf("%s, ", ata_mode2string(pata->mode)); 1143236437Smav if ((pata->valid & CTS_ATA_VALID_ATAPI) && pata->atapi != 0) 1144236437Smav printf("ATAPI %dbytes, ", pata->atapi); 1145236437Smav if (pata->valid & CTS_ATA_VALID_BYTECOUNT) 1146236437Smav printf("PIO %dbytes", pata->bytecount); 1147199747Smav printf(")"); 1148198709Smav } else if (ccb->cts.transport == XPORT_SATA) { 1149198709Smav struct ccb_trans_settings_sata *sata = 1150198709Smav &ccb->cts.xport_specific.sata; 115146581Sken 1152199747Smav printf(" ("); 1153199747Smav if (sata->valid & CTS_SATA_VALID_REVISION) 1154199747Smav printf("SATA %d.x, ", sata->revision); 1155204195Smav else 1156204195Smav printf("SATA, "); 1157199747Smav if (sata->valid & CTS_SATA_VALID_MODE) 1158199747Smav printf("%s, ", ata_mode2string(sata->mode)); 1159203376Smav if ((sata->valid & CTS_SATA_VALID_ATAPI) && sata->atapi != 0) 1160203376Smav printf("ATAPI %dbytes, ", sata->atapi); 1161199747Smav if (sata->valid & CTS_SATA_VALID_BYTECOUNT) 1162203376Smav printf("PIO %dbytes", sata->bytecount); 1163199747Smav printf(")"); 1164163896Smjacob } 116539214Sgibbs 1166163896Smjacob if (ccb->cts.protocol == PROTO_SCSI) { 1167163896Smjacob struct ccb_trans_settings_scsi *scsi = 1168163896Smjacob &ccb->cts.proto_specific.scsi; 1169163896Smjacob if (scsi->valid & CTS_SCSI_VALID_TQ) { 1170164842Smjacob if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) { 1171163896Smjacob fprintf(stdout, ", Command Queueing Enabled"); 1172164842Smjacob } 117346581Sken } 117446581Sken } 117546581Sken 117639214Sgibbs fprintf(stdout, "\n"); 117739214Sgibbs 117846581Skenxferrate_bailout: 117946581Sken 118046581Sken cam_freeccb(ccb); 118146581Sken 118246581Sken return(retval); 118339214Sgibbs} 1184195534Sscottl 1185195534Sscottlstatic void 1186249895Ssmhatahpa_print(struct ata_params *parm, u_int64_t hpasize, int header) 1187249895Ssmh{ 1188249895Ssmh u_int32_t lbasize = (u_int32_t)parm->lba_size_1 | 1189249895Ssmh ((u_int32_t)parm->lba_size_2 << 16); 1190249895Ssmh 1191249895Ssmh u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) | 1192249895Ssmh ((u_int64_t)parm->lba_size48_2 << 16) | 1193249895Ssmh ((u_int64_t)parm->lba_size48_3 << 32) | 1194249895Ssmh ((u_int64_t)parm->lba_size48_4 << 48); 1195249895Ssmh 1196249895Ssmh if (header) { 1197249895Ssmh printf("\nFeature " 1198249895Ssmh "Support Enabled Value\n"); 1199249895Ssmh } 1200249895Ssmh 1201249895Ssmh printf("Host Protected Area (HPA) "); 1202249895Ssmh if (parm->support.command1 & ATA_SUPPORT_PROTECTED) { 1203249895Ssmh u_int64_t lba = lbasize48 ? lbasize48 : lbasize; 1204249895Ssmh printf("yes %s %ju/%ju\n", (hpasize > lba) ? "yes" : "no ", 1205249895Ssmh lba, hpasize); 1206249895Ssmh 1207249895Ssmh printf("HPA - Security "); 1208249895Ssmh if (parm->support.command1 & ATA_SUPPORT_MAXSECURITY) 1209249895Ssmh printf("yes\n"); 1210249895Ssmh else 1211249895Ssmh printf("no\n"); 1212249895Ssmh } else { 1213249895Ssmh printf("no\n"); 1214249895Ssmh } 1215249895Ssmh} 1216249895Ssmh 1217249895Ssmhstatic void 1218195534Sscottlatacapprint(struct ata_params *parm) 1219195534Sscottl{ 1220195534Sscottl u_int32_t lbasize = (u_int32_t)parm->lba_size_1 | 1221195534Sscottl ((u_int32_t)parm->lba_size_2 << 16); 1222195534Sscottl 1223195534Sscottl u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) | 1224195534Sscottl ((u_int64_t)parm->lba_size48_2 << 16) | 1225195534Sscottl ((u_int64_t)parm->lba_size48_3 << 32) | 1226195534Sscottl ((u_int64_t)parm->lba_size48_4 << 48); 1227195534Sscottl 1228195534Sscottl printf("\n"); 1229196658Smav printf("protocol "); 1230196658Smav printf("ATA/ATAPI-%d", ata_version(parm->version_major)); 1231195534Sscottl if (parm->satacapabilities && parm->satacapabilities != 0xffff) { 1232197545Smav if (parm->satacapabilities & ATA_SATA_GEN3) 1233197545Smav printf(" SATA 3.x\n"); 1234197545Smav else if (parm->satacapabilities & ATA_SATA_GEN2) 1235196658Smav printf(" SATA 2.x\n"); 1236195534Sscottl else if (parm->satacapabilities & ATA_SATA_GEN1) 1237196658Smav printf(" SATA 1.x\n"); 1238195534Sscottl else 1239197545Smav printf(" SATA\n"); 1240195534Sscottl } 1241195534Sscottl else 1242196658Smav printf("\n"); 1243195534Sscottl printf("device model %.40s\n", parm->model); 1244197545Smav printf("firmware revision %.8s\n", parm->revision); 1245195534Sscottl printf("serial number %.20s\n", parm->serial); 1246197545Smav if (parm->enabled.extension & ATA_SUPPORT_64BITWWN) { 1247225018Smav printf("WWN %04x%04x%04x%04x\n", 1248197545Smav parm->wwn[0], parm->wwn[1], parm->wwn[2], parm->wwn[3]); 1249197545Smav } 1250197545Smav if (parm->enabled.extension & ATA_SUPPORT_MEDIASN) { 1251197545Smav printf("media serial number %.30s\n", 1252197545Smav parm->media_serial); 1253197545Smav } 1254195534Sscottl 1255195534Sscottl printf("cylinders %d\n", parm->cylinders); 1256195534Sscottl printf("heads %d\n", parm->heads); 1257195534Sscottl printf("sectors/track %d\n", parm->sectors); 1258198897Smav printf("sector size logical %u, physical %lu, offset %lu\n", 1259198897Smav ata_logical_sector_size(parm), 1260198897Smav (unsigned long)ata_physical_sector_size(parm), 1261198897Smav (unsigned long)ata_logical_sector_offset(parm)); 1262195534Sscottl 1263195534Sscottl if (parm->config == ATA_PROTO_CFA || 1264195534Sscottl (parm->support.command2 & ATA_SUPPORT_CFA)) 1265195534Sscottl printf("CFA supported\n"); 1266195534Sscottl 1267196658Smav printf("LBA%ssupported ", 1268195534Sscottl parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not "); 1269195534Sscottl if (lbasize) 1270195534Sscottl printf("%d sectors\n", lbasize); 1271195534Sscottl else 1272195534Sscottl printf("\n"); 1273195534Sscottl 1274196658Smav printf("LBA48%ssupported ", 1275195534Sscottl parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not "); 1276195534Sscottl if (lbasize48) 1277195534Sscottl printf("%ju sectors\n", (uintmax_t)lbasize48); 1278195534Sscottl else 1279195534Sscottl printf("\n"); 1280195534Sscottl 1281196658Smav printf("PIO supported PIO"); 1282197419Smav switch (ata_max_pmode(parm)) { 1283197419Smav case ATA_PIO4: 1284196658Smav printf("4"); 1285197419Smav break; 1286197419Smav case ATA_PIO3: 1287196658Smav printf("3"); 1288197419Smav break; 1289197419Smav case ATA_PIO2: 1290196658Smav printf("2"); 1291197419Smav break; 1292197419Smav case ATA_PIO1: 1293196658Smav printf("1"); 1294197419Smav break; 1295197419Smav default: 1296196658Smav printf("0"); 1297197419Smav } 1298197545Smav if ((parm->capabilities1 & ATA_SUPPORT_IORDY) == 0) 1299197545Smav printf(" w/o IORDY"); 1300196658Smav printf("\n"); 1301196658Smav 1302196658Smav printf("DMA%ssupported ", 1303195534Sscottl parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not "); 1304196658Smav if (parm->capabilities1 & ATA_SUPPORT_DMA) { 1305196658Smav if (parm->mwdmamodes & 0xff) { 1306196658Smav printf("WDMA"); 1307196658Smav if (parm->mwdmamodes & 0x04) 1308196658Smav printf("2"); 1309196658Smav else if (parm->mwdmamodes & 0x02) 1310196658Smav printf("1"); 1311196658Smav else if (parm->mwdmamodes & 0x01) 1312196658Smav printf("0"); 1313196658Smav printf(" "); 1314196658Smav } 1315196658Smav if ((parm->atavalid & ATA_FLAG_88) && 1316196658Smav (parm->udmamodes & 0xff)) { 1317196658Smav printf("UDMA"); 1318196658Smav if (parm->udmamodes & 0x40) 1319196658Smav printf("6"); 1320196658Smav else if (parm->udmamodes & 0x20) 1321196658Smav printf("5"); 1322196658Smav else if (parm->udmamodes & 0x10) 1323196658Smav printf("4"); 1324196658Smav else if (parm->udmamodes & 0x08) 1325196658Smav printf("3"); 1326196658Smav else if (parm->udmamodes & 0x04) 1327196658Smav printf("2"); 1328196658Smav else if (parm->udmamodes & 0x02) 1329196658Smav printf("1"); 1330196658Smav else if (parm->udmamodes & 0x01) 1331196658Smav printf("0"); 1332196658Smav printf(" "); 1333196658Smav } 1334196658Smav } 1335196658Smav printf("\n"); 1336195534Sscottl 1337197545Smav if (parm->media_rotation_rate == 1) { 1338197545Smav printf("media RPM non-rotating\n"); 1339197545Smav } else if (parm->media_rotation_rate >= 0x0401 && 1340197545Smav parm->media_rotation_rate <= 0xFFFE) { 1341197545Smav printf("media RPM %d\n", 1342197545Smav parm->media_rotation_rate); 1343197545Smav } 1344195534Sscottl 1345195534Sscottl printf("\nFeature " 1346214321Smav "Support Enabled Value Vendor\n"); 1347197545Smav printf("read ahead %s %s\n", 1348197545Smav parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no", 1349197545Smav parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no"); 1350195534Sscottl printf("write cache %s %s\n", 1351195534Sscottl parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no", 1352195534Sscottl parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no"); 1353197545Smav printf("flush cache %s %s\n", 1354197545Smav parm->support.command2 & ATA_SUPPORT_FLUSHCACHE ? "yes" : "no", 1355197545Smav parm->enabled.command2 & ATA_SUPPORT_FLUSHCACHE ? "yes" : "no"); 1356202694Smav printf("overlap %s\n", 1357202694Smav parm->capabilities1 & ATA_SUPPORT_OVERLAP ? "yes" : "no"); 1358202694Smav printf("Tagged Command Queuing (TCQ) %s %s", 1359202694Smav parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no", 1360202694Smav parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no"); 1361202694Smav if (parm->support.command2 & ATA_SUPPORT_QUEUED) { 1362202694Smav printf(" %d tags\n", 1363202694Smav ATA_QUEUE_LEN(parm->queue) + 1); 1364202694Smav } else 1365202694Smav printf("\n"); 1366214321Smav printf("Native Command Queuing (NCQ) "); 1367214321Smav if (parm->satacapabilities != 0xffff && 1368214321Smav (parm->satacapabilities & ATA_SUPPORT_NCQ)) { 1369214321Smav printf("yes %d tags\n", 1370214321Smav ATA_QUEUE_LEN(parm->queue) + 1); 1371214321Smav } else 1372214321Smav printf("no\n"); 1373195534Sscottl printf("SMART %s %s\n", 1374195534Sscottl parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no", 1375195534Sscottl parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no"); 1376195534Sscottl printf("microcode download %s %s\n", 1377195534Sscottl parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no", 1378195534Sscottl parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no"); 1379195534Sscottl printf("security %s %s\n", 1380195534Sscottl parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no", 1381195534Sscottl parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no"); 1382195534Sscottl printf("power management %s %s\n", 1383195534Sscottl parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no", 1384195534Sscottl parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no"); 1385214321Smav printf("advanced power management %s %s", 1386195534Sscottl parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no", 1387214321Smav parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no"); 1388214321Smav if (parm->support.command2 & ATA_SUPPORT_APM) { 1389214321Smav printf(" %d/0x%02X\n", 1390214321Smav parm->apm_value, parm->apm_value); 1391214321Smav } else 1392214321Smav printf("\n"); 1393214321Smav printf("automatic acoustic management %s %s", 1394195534Sscottl parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no", 1395214321Smav parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no"); 1396214321Smav if (parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC) { 1397214321Smav printf(" %d/0x%02X %d/0x%02X\n", 1398214321Smav ATA_ACOUSTIC_CURRENT(parm->acoustic), 1399214321Smav ATA_ACOUSTIC_CURRENT(parm->acoustic), 1400214321Smav ATA_ACOUSTIC_VENDOR(parm->acoustic), 1401214321Smav ATA_ACOUSTIC_VENDOR(parm->acoustic)); 1402214321Smav } else 1403214321Smav printf("\n"); 1404197545Smav printf("media status notification %s %s\n", 1405197545Smav parm->support.command2 & ATA_SUPPORT_NOTIFY ? "yes" : "no", 1406197545Smav parm->enabled.command2 & ATA_SUPPORT_NOTIFY ? "yes" : "no"); 1407197545Smav printf("power-up in Standby %s %s\n", 1408197545Smav parm->support.command2 & ATA_SUPPORT_STANDBY ? "yes" : "no", 1409197545Smav parm->enabled.command2 & ATA_SUPPORT_STANDBY ? "yes" : "no"); 1410214321Smav printf("write-read-verify %s %s", 1411197545Smav parm->support2 & ATA_SUPPORT_WRITEREADVERIFY ? "yes" : "no", 1412214321Smav parm->enabled2 & ATA_SUPPORT_WRITEREADVERIFY ? "yes" : "no"); 1413214321Smav if (parm->support2 & ATA_SUPPORT_WRITEREADVERIFY) { 1414214321Smav printf(" %d/0x%x\n", 1415214321Smav parm->wrv_mode, parm->wrv_mode); 1416214321Smav } else 1417214321Smav printf("\n"); 1418197545Smav printf("unload %s %s\n", 1419197545Smav parm->support.extension & ATA_SUPPORT_UNLOAD ? "yes" : "no", 1420197545Smav parm->enabled.extension & ATA_SUPPORT_UNLOAD ? "yes" : "no"); 1421197545Smav printf("free-fall %s %s\n", 1422197545Smav parm->support2 & ATA_SUPPORT_FREEFALL ? "yes" : "no", 1423197545Smav parm->enabled2 & ATA_SUPPORT_FREEFALL ? "yes" : "no"); 1424249115Ssmh printf("Data Set Management (DSM/TRIM) "); 1425249115Ssmh if (parm->support_dsm & ATA_SUPPORT_DSM_TRIM) { 1426249115Ssmh printf("yes\n"); 1427249115Ssmh printf("DSM - max 512byte blocks "); 1428249115Ssmh if (parm->max_dsm_blocks == 0x00) 1429249115Ssmh printf("yes not specified\n"); 1430249115Ssmh else 1431249115Ssmh printf("yes %d\n", 1432249115Ssmh parm->max_dsm_blocks); 1433249115Ssmh 1434249115Ssmh printf("DSM - deterministic read "); 1435249115Ssmh if (parm->support3 & ATA_SUPPORT_DRAT) { 1436249115Ssmh if (parm->support3 & ATA_SUPPORT_RZAT) 1437249115Ssmh printf("yes zeroed\n"); 1438249115Ssmh else 1439249115Ssmh printf("yes any value\n"); 1440249115Ssmh } else { 1441249115Ssmh printf("no\n"); 1442249115Ssmh } 1443249115Ssmh } else { 1444249115Ssmh printf("no\n"); 1445249115Ssmh } 1446195534Sscottl} 1447195534Sscottl 1448195534Sscottlstatic int 1449249115Ssmhscsi_cam_pass_16_send(struct cam_device *device, union ccb *ccb, int quiet) 1450195534Sscottl{ 1451249115Ssmh struct ata_pass_16 *ata_pass_16; 1452249115Ssmh struct ata_cmd ata_cmd; 1453196658Smav 1454249115Ssmh ata_pass_16 = (struct ata_pass_16 *)ccb->csio.cdb_io.cdb_bytes; 1455249115Ssmh ata_cmd.command = ata_pass_16->command; 1456249115Ssmh ata_cmd.control = ata_pass_16->control; 1457249115Ssmh ata_cmd.features = ata_pass_16->features; 1458249115Ssmh 1459249115Ssmh if (arglist & CAM_ARG_VERBOSE) { 1460249115Ssmh warnx("sending ATA %s via pass_16 with timeout of %u msecs", 1461249115Ssmh ata_op_string(&ata_cmd), 1462249115Ssmh ccb->csio.ccb_h.timeout); 1463196658Smav } 1464195534Sscottl 1465249115Ssmh /* Disable freezing the device queue */ 1466249115Ssmh ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 1467249115Ssmh 1468249115Ssmh if (arglist & CAM_ARG_ERR_RECOVER) 1469249115Ssmh ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 1470249115Ssmh 1471249115Ssmh if (cam_send_ccb(device, ccb) < 0) { 1472249115Ssmh if (quiet != 1 || arglist & CAM_ARG_VERBOSE) { 1473249115Ssmh warn("error sending ATA %s via pass_16", 1474249115Ssmh ata_op_string(&ata_cmd)); 1475249115Ssmh } 1476249115Ssmh 1477249115Ssmh if (arglist & CAM_ARG_VERBOSE) { 1478249115Ssmh cam_error_print(device, ccb, CAM_ESF_ALL, 1479249115Ssmh CAM_EPF_ALL, stderr); 1480249115Ssmh } 1481249115Ssmh 1482249115Ssmh return (1); 1483195534Sscottl } 1484195534Sscottl 1485249115Ssmh if (!(ata_pass_16->flags & AP_FLAG_CHK_COND) && 1486249115Ssmh (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1487249115Ssmh if (quiet != 1 || arglist & CAM_ARG_VERBOSE) { 1488249115Ssmh warnx("ATA %s via pass_16 failed", 1489249115Ssmh ata_op_string(&ata_cmd)); 1490249115Ssmh } 1491249115Ssmh if (arglist & CAM_ARG_VERBOSE) { 1492249115Ssmh cam_error_print(device, ccb, CAM_ESF_ALL, 1493249115Ssmh CAM_EPF_ALL, stderr); 1494249115Ssmh } 1495195534Sscottl 1496249115Ssmh return (1); 1497249115Ssmh } 1498195534Sscottl 1499249115Ssmh return (0); 1500249115Ssmh} 1501249115Ssmh 1502249115Ssmh 1503249115Ssmhstatic int 1504249115Ssmhata_cam_send(struct cam_device *device, union ccb *ccb, int quiet) 1505249115Ssmh{ 1506249115Ssmh if (arglist & CAM_ARG_VERBOSE) { 1507249115Ssmh warnx("sending ATA %s with timeout of %u msecs", 1508249115Ssmh ata_op_string(&(ccb->ataio.cmd)), 1509249115Ssmh ccb->ataio.ccb_h.timeout); 1510195534Sscottl } 1511195534Sscottl 1512195534Sscottl /* Disable freezing the device queue */ 1513195534Sscottl ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 1514195534Sscottl 1515195534Sscottl if (arglist & CAM_ARG_ERR_RECOVER) 1516195534Sscottl ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 1517195534Sscottl 1518195534Sscottl if (cam_send_ccb(device, ccb) < 0) { 1519249115Ssmh if (quiet != 1 || arglist & CAM_ARG_VERBOSE) { 1520249115Ssmh warn("error sending ATA %s", 1521249115Ssmh ata_op_string(&(ccb->ataio.cmd))); 1522249115Ssmh } 1523195534Sscottl 1524195534Sscottl if (arglist & CAM_ARG_VERBOSE) { 1525195534Sscottl cam_error_print(device, ccb, CAM_ESF_ALL, 1526195534Sscottl CAM_EPF_ALL, stderr); 1527195534Sscottl } 1528195534Sscottl 1529249115Ssmh return (1); 1530195534Sscottl } 1531195534Sscottl 1532195534Sscottl if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1533249115Ssmh if (quiet != 1 || arglist & CAM_ARG_VERBOSE) { 1534249115Ssmh warnx("ATA %s failed: %d", 1535249115Ssmh ata_op_string(&(ccb->ataio.cmd)), quiet); 1536249115Ssmh } 1537195534Sscottl 1538195534Sscottl if (arglist & CAM_ARG_VERBOSE) { 1539195534Sscottl cam_error_print(device, ccb, CAM_ESF_ALL, 1540195534Sscottl CAM_EPF_ALL, stderr); 1541195534Sscottl } 1542249115Ssmh 1543249115Ssmh return (1); 1544195534Sscottl } 1545195534Sscottl 1546249115Ssmh return (0); 1547249115Ssmh} 1548195534Sscottl 1549249115Ssmhstatic int 1550249115Ssmhata_do_pass_16(struct cam_device *device, union ccb *ccb, int retries, 1551249115Ssmh u_int32_t flags, u_int8_t protocol, u_int8_t ata_flags, 1552249115Ssmh u_int8_t tag_action, u_int8_t command, u_int8_t features, 1553249115Ssmh u_int64_t lba, u_int8_t sector_count, u_int8_t *data_ptr, 1554249115Ssmh u_int16_t dxfer_len, int timeout, int quiet) 1555249115Ssmh{ 1556249115Ssmh if (data_ptr != NULL) { 1557249115Ssmh ata_flags |= AP_FLAG_BYT_BLOK_BYTES | 1558249115Ssmh AP_FLAG_TLEN_SECT_CNT; 1559249115Ssmh if (flags & CAM_DIR_OUT) 1560249115Ssmh ata_flags |= AP_FLAG_TDIR_TO_DEV; 1561249115Ssmh else 1562249115Ssmh ata_flags |= AP_FLAG_TDIR_FROM_DEV; 1563249115Ssmh } else { 1564249115Ssmh ata_flags |= AP_FLAG_TLEN_NO_DATA; 1565249115Ssmh } 1566249115Ssmh 1567249115Ssmh bzero(&(&ccb->ccb_h)[1], 1568249115Ssmh sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 1569249115Ssmh 1570249115Ssmh scsi_ata_pass_16(&ccb->csio, 1571249115Ssmh retries, 1572249115Ssmh NULL, 1573249115Ssmh flags, 1574249115Ssmh tag_action, 1575249115Ssmh protocol, 1576249115Ssmh ata_flags, 1577249115Ssmh features, 1578249115Ssmh sector_count, 1579249115Ssmh lba, 1580249115Ssmh command, 1581249115Ssmh /*control*/0, 1582249115Ssmh data_ptr, 1583249115Ssmh dxfer_len, 1584249115Ssmh /*sense_len*/SSD_FULL_SIZE, 1585249115Ssmh timeout); 1586249115Ssmh 1587249115Ssmh return scsi_cam_pass_16_send(device, ccb, quiet); 1588249115Ssmh} 1589249115Ssmh 1590249115Ssmhstatic int 1591249115Ssmhata_try_pass_16(struct cam_device *device) 1592249115Ssmh{ 1593249115Ssmh struct ccb_pathinq cpi; 1594249115Ssmh 1595249115Ssmh if (get_cpi(device, &cpi) != 0) { 1596249115Ssmh warnx("couldn't get CPI"); 1597249115Ssmh return (-1); 1598249115Ssmh } 1599249115Ssmh 1600249115Ssmh if (cpi.protocol == PROTO_SCSI) { 1601249115Ssmh /* possibly compatible with pass_16 */ 1602249115Ssmh return (1); 1603249115Ssmh } 1604249115Ssmh 1605249115Ssmh /* likely not compatible with pass_16 */ 1606249115Ssmh return (0); 1607249115Ssmh} 1608249115Ssmh 1609249115Ssmhstatic int 1610249115Ssmhata_do_28bit_cmd(struct cam_device *device, union ccb *ccb, int retries, 1611249115Ssmh u_int32_t flags, u_int8_t protocol, u_int8_t tag_action, 1612249115Ssmh u_int8_t command, u_int8_t features, u_int32_t lba, 1613249115Ssmh u_int8_t sector_count, u_int8_t *data_ptr, u_int16_t dxfer_len, 1614249115Ssmh int timeout, int quiet) 1615249115Ssmh{ 1616249115Ssmh 1617249115Ssmh 1618249115Ssmh switch (ata_try_pass_16(device)) { 1619249115Ssmh case -1: 1620249115Ssmh return (1); 1621249115Ssmh case 1: 1622249115Ssmh /* Try using SCSI Passthrough */ 1623249115Ssmh return ata_do_pass_16(device, ccb, retries, flags, protocol, 1624249115Ssmh 0, tag_action, command, features, lba, 1625249115Ssmh sector_count, data_ptr, dxfer_len, 1626249115Ssmh timeout, quiet); 1627249115Ssmh } 1628249115Ssmh 1629249115Ssmh bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_ataio) - 1630249115Ssmh sizeof(struct ccb_hdr)); 1631249115Ssmh cam_fill_ataio(&ccb->ataio, 1632249115Ssmh retries, 1633249115Ssmh NULL, 1634249115Ssmh flags, 1635249115Ssmh tag_action, 1636249115Ssmh data_ptr, 1637249115Ssmh dxfer_len, 1638249115Ssmh timeout); 1639249115Ssmh 1640249115Ssmh ata_28bit_cmd(&ccb->ataio, command, features, lba, sector_count); 1641249115Ssmh return ata_cam_send(device, ccb, quiet); 1642249115Ssmh} 1643249115Ssmh 1644249895Ssmhstatic int 1645249895Ssmhata_do_cmd(struct cam_device *device, union ccb *ccb, int retries, 1646249895Ssmh u_int32_t flags, u_int8_t protocol, u_int8_t ata_flags, 1647249895Ssmh u_int8_t tag_action, u_int8_t command, u_int8_t features, 1648249895Ssmh u_int64_t lba, u_int8_t sector_count, u_int8_t *data_ptr, 1649249895Ssmh u_int16_t dxfer_len, int timeout, int force48bit) 1650249895Ssmh{ 1651249895Ssmh int retval; 1652249895Ssmh 1653249895Ssmh retval = ata_try_pass_16(device); 1654249895Ssmh if (retval == -1) 1655249895Ssmh return (1); 1656249895Ssmh 1657249895Ssmh if (retval == 1) { 1658249895Ssmh int error; 1659249895Ssmh 1660249895Ssmh /* Try using SCSI Passthrough */ 1661249895Ssmh error = ata_do_pass_16(device, ccb, retries, flags, protocol, 1662249895Ssmh ata_flags, tag_action, command, features, 1663249895Ssmh lba, sector_count, data_ptr, dxfer_len, 1664249895Ssmh timeout, 0); 1665249895Ssmh 1666249895Ssmh if (ata_flags & AP_FLAG_CHK_COND) { 1667249895Ssmh /* Decode ata_res from sense data */ 1668249895Ssmh struct ata_res_pass16 *res_pass16; 1669249895Ssmh struct ata_res *res; 1670249895Ssmh u_int i; 1671249895Ssmh u_int16_t *ptr; 1672249895Ssmh 1673249895Ssmh /* sense_data is 4 byte aligned */ 1674249895Ssmh ptr = (uint16_t*)(uintptr_t)&ccb->csio.sense_data; 1675249895Ssmh for (i = 0; i < sizeof(*res_pass16) / 2; i++) 1676249895Ssmh ptr[i] = le16toh(ptr[i]); 1677249895Ssmh 1678249895Ssmh /* sense_data is 4 byte aligned */ 1679249895Ssmh res_pass16 = (struct ata_res_pass16 *)(uintptr_t) 1680249895Ssmh &ccb->csio.sense_data; 1681249895Ssmh res = &ccb->ataio.res; 1682249895Ssmh res->flags = res_pass16->flags; 1683249895Ssmh res->status = res_pass16->status; 1684249895Ssmh res->error = res_pass16->error; 1685249895Ssmh res->lba_low = res_pass16->lba_low; 1686249895Ssmh res->lba_mid = res_pass16->lba_mid; 1687249895Ssmh res->lba_high = res_pass16->lba_high; 1688249895Ssmh res->device = res_pass16->device; 1689249895Ssmh res->lba_low_exp = res_pass16->lba_low_exp; 1690249895Ssmh res->lba_mid_exp = res_pass16->lba_mid_exp; 1691249895Ssmh res->lba_high_exp = res_pass16->lba_high_exp; 1692249895Ssmh res->sector_count = res_pass16->sector_count; 1693249895Ssmh res->sector_count_exp = res_pass16->sector_count_exp; 1694249895Ssmh } 1695249895Ssmh 1696249895Ssmh return (error); 1697249895Ssmh } 1698249895Ssmh 1699249895Ssmh bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_ataio) - 1700249895Ssmh sizeof(struct ccb_hdr)); 1701249895Ssmh cam_fill_ataio(&ccb->ataio, 1702249895Ssmh retries, 1703249895Ssmh NULL, 1704249895Ssmh flags, 1705249895Ssmh tag_action, 1706249895Ssmh data_ptr, 1707249895Ssmh dxfer_len, 1708249895Ssmh timeout); 1709249895Ssmh 1710249895Ssmh if (force48bit || lba > ATA_MAX_28BIT_LBA) 1711249895Ssmh ata_48bit_cmd(&ccb->ataio, command, features, lba, sector_count); 1712249895Ssmh else 1713249895Ssmh ata_28bit_cmd(&ccb->ataio, command, features, lba, sector_count); 1714249895Ssmh 1715249895Ssmh if (ata_flags & AP_FLAG_CHK_COND) 1716249895Ssmh ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT; 1717249895Ssmh 1718249895Ssmh return ata_cam_send(device, ccb, 0); 1719249895Ssmh} 1720249895Ssmh 1721249115Ssmhstatic void 1722249115Ssmhdump_data(uint16_t *ptr, uint32_t len) 1723249115Ssmh{ 1724249115Ssmh u_int i; 1725249115Ssmh 1726249115Ssmh for (i = 0; i < len / 2; i++) { 1727249115Ssmh if ((i % 8) == 0) 1728249115Ssmh printf(" %3d: ", i); 1729249115Ssmh printf("%04hx ", ptr[i]); 1730249115Ssmh if ((i % 8) == 7) 1731249115Ssmh printf("\n"); 1732249115Ssmh } 1733249115Ssmh if ((i % 8) != 7) 1734249115Ssmh printf("\n"); 1735249115Ssmh} 1736249115Ssmh 1737249115Ssmhstatic int 1738249895Ssmhatahpa_proc_resp(struct cam_device *device, union ccb *ccb, 1739249895Ssmh int is48bit, u_int64_t *hpasize) 1740249895Ssmh{ 1741249895Ssmh struct ata_res *res; 1742249895Ssmh 1743249895Ssmh res = &ccb->ataio.res; 1744249895Ssmh if (res->status & ATA_STATUS_ERROR) { 1745249895Ssmh if (arglist & CAM_ARG_VERBOSE) { 1746249895Ssmh cam_error_print(device, ccb, CAM_ESF_ALL, 1747249895Ssmh CAM_EPF_ALL, stderr); 1748249895Ssmh printf("error = 0x%02x, sector_count = 0x%04x, " 1749249895Ssmh "device = 0x%02x, status = 0x%02x\n", 1750249895Ssmh res->error, res->sector_count, 1751249895Ssmh res->device, res->status); 1752249895Ssmh } 1753249895Ssmh 1754249895Ssmh if (res->error & ATA_ERROR_ID_NOT_FOUND) { 1755249895Ssmh warnx("Max address has already been set since " 1756249895Ssmh "last power-on or hardware reset"); 1757249895Ssmh } 1758249895Ssmh 1759249895Ssmh return (1); 1760249895Ssmh } 1761249895Ssmh 1762249895Ssmh if (arglist & CAM_ARG_VERBOSE) { 1763249895Ssmh fprintf(stdout, "%s%d: Raw native max data:\n", 1764249895Ssmh device->device_name, device->dev_unit_num); 1765249895Ssmh /* res is 4 byte aligned */ 1766249895Ssmh dump_data((uint16_t*)(uintptr_t)res, sizeof(struct ata_res)); 1767249895Ssmh 1768249895Ssmh printf("error = 0x%02x, sector_count = 0x%04x, device = 0x%02x, " 1769249895Ssmh "status = 0x%02x\n", res->error, res->sector_count, 1770249895Ssmh res->device, res->status); 1771249895Ssmh } 1772249895Ssmh 1773249895Ssmh if (hpasize != NULL) { 1774249895Ssmh if (is48bit) { 1775249895Ssmh *hpasize = (((u_int64_t)((res->lba_high_exp << 16) | 1776249895Ssmh (res->lba_mid_exp << 8) | res->lba_low_exp) << 24) | 1777249895Ssmh ((res->lba_high << 16) | (res->lba_mid << 8) | 1778249895Ssmh res->lba_low)) + 1; 1779249895Ssmh } else { 1780249895Ssmh *hpasize = (((res->device & 0x0f) << 24) | 1781249895Ssmh (res->lba_high << 16) | (res->lba_mid << 8) | 1782249895Ssmh res->lba_low) + 1; 1783249895Ssmh } 1784249895Ssmh } 1785249895Ssmh 1786249895Ssmh return (0); 1787249895Ssmh} 1788249895Ssmh 1789249895Ssmhstatic int 1790249895Ssmhata_read_native_max(struct cam_device *device, int retry_count, 1791249895Ssmh u_int32_t timeout, union ccb *ccb, 1792249895Ssmh struct ata_params *parm, u_int64_t *hpasize) 1793249895Ssmh{ 1794249895Ssmh int error; 1795249895Ssmh u_int cmd, is48bit; 1796249895Ssmh u_int8_t protocol; 1797249895Ssmh 1798249895Ssmh is48bit = parm->support.command2 & ATA_SUPPORT_ADDRESS48; 1799249895Ssmh protocol = AP_PROTO_NON_DATA; 1800249895Ssmh 1801249895Ssmh if (is48bit) { 1802249895Ssmh cmd = ATA_READ_NATIVE_MAX_ADDRESS48; 1803249895Ssmh protocol |= AP_EXTEND; 1804249895Ssmh } else { 1805249895Ssmh cmd = ATA_READ_NATIVE_MAX_ADDRESS; 1806249895Ssmh } 1807249895Ssmh 1808249895Ssmh error = ata_do_cmd(device, 1809249895Ssmh ccb, 1810249895Ssmh retry_count, 1811251659Smav /*flags*/CAM_DIR_NONE, 1812249895Ssmh /*protocol*/protocol, 1813249895Ssmh /*ata_flags*/AP_FLAG_CHK_COND, 1814249895Ssmh /*tag_action*/MSG_SIMPLE_Q_TAG, 1815249895Ssmh /*command*/cmd, 1816249895Ssmh /*features*/0, 1817249895Ssmh /*lba*/0, 1818249895Ssmh /*sector_count*/0, 1819249895Ssmh /*data_ptr*/NULL, 1820249895Ssmh /*dxfer_len*/0, 1821249895Ssmh timeout ? timeout : 1000, 1822249895Ssmh is48bit); 1823249895Ssmh 1824249895Ssmh if (error) 1825249895Ssmh return (error); 1826249895Ssmh 1827249895Ssmh return atahpa_proc_resp(device, ccb, is48bit, hpasize); 1828249895Ssmh} 1829249895Ssmh 1830249895Ssmhstatic int 1831249895Ssmhatahpa_set_max(struct cam_device *device, int retry_count, 1832249895Ssmh u_int32_t timeout, union ccb *ccb, 1833249895Ssmh int is48bit, u_int64_t maxsize, int persist) 1834249895Ssmh{ 1835249895Ssmh int error; 1836249895Ssmh u_int cmd; 1837249895Ssmh u_int8_t protocol; 1838249895Ssmh 1839249895Ssmh protocol = AP_PROTO_NON_DATA; 1840249895Ssmh 1841249895Ssmh if (is48bit) { 1842249895Ssmh cmd = ATA_SET_MAX_ADDRESS48; 1843249895Ssmh protocol |= AP_EXTEND; 1844249895Ssmh } else { 1845249895Ssmh cmd = ATA_SET_MAX_ADDRESS; 1846249895Ssmh } 1847249895Ssmh 1848249895Ssmh /* lba's are zero indexed so the max lba is requested max - 1 */ 1849249895Ssmh if (maxsize) 1850249895Ssmh maxsize--; 1851249895Ssmh 1852249895Ssmh error = ata_do_cmd(device, 1853249895Ssmh ccb, 1854249895Ssmh retry_count, 1855251659Smav /*flags*/CAM_DIR_NONE, 1856249895Ssmh /*protocol*/protocol, 1857249895Ssmh /*ata_flags*/AP_FLAG_CHK_COND, 1858249895Ssmh /*tag_action*/MSG_SIMPLE_Q_TAG, 1859249895Ssmh /*command*/cmd, 1860249895Ssmh /*features*/ATA_HPA_FEAT_MAX_ADDR, 1861249895Ssmh /*lba*/maxsize, 1862249895Ssmh /*sector_count*/persist, 1863249895Ssmh /*data_ptr*/NULL, 1864249895Ssmh /*dxfer_len*/0, 1865249895Ssmh timeout ? timeout : 1000, 1866249895Ssmh is48bit); 1867249895Ssmh 1868249895Ssmh if (error) 1869249895Ssmh return (error); 1870249895Ssmh 1871249895Ssmh return atahpa_proc_resp(device, ccb, is48bit, NULL); 1872249895Ssmh} 1873249895Ssmh 1874249895Ssmhstatic int 1875249895Ssmhatahpa_password(struct cam_device *device, int retry_count, 1876249895Ssmh u_int32_t timeout, union ccb *ccb, 1877249895Ssmh int is48bit, struct ata_set_max_pwd *pwd) 1878249895Ssmh{ 1879249895Ssmh int error; 1880249895Ssmh u_int cmd; 1881249895Ssmh u_int8_t protocol; 1882249895Ssmh 1883249895Ssmh protocol = AP_PROTO_PIO_OUT; 1884249895Ssmh cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS; 1885249895Ssmh 1886249895Ssmh error = ata_do_cmd(device, 1887249895Ssmh ccb, 1888249895Ssmh retry_count, 1889249895Ssmh /*flags*/CAM_DIR_OUT, 1890249895Ssmh /*protocol*/protocol, 1891249895Ssmh /*ata_flags*/AP_FLAG_CHK_COND, 1892249895Ssmh /*tag_action*/MSG_SIMPLE_Q_TAG, 1893249895Ssmh /*command*/cmd, 1894249895Ssmh /*features*/ATA_HPA_FEAT_SET_PWD, 1895249895Ssmh /*lba*/0, 1896249895Ssmh /*sector_count*/0, 1897249895Ssmh /*data_ptr*/(u_int8_t*)pwd, 1898249895Ssmh /*dxfer_len*/sizeof(struct ata_set_max_pwd), 1899249895Ssmh timeout ? timeout : 1000, 1900249895Ssmh is48bit); 1901249895Ssmh 1902249895Ssmh if (error) 1903249895Ssmh return (error); 1904249895Ssmh 1905249895Ssmh return atahpa_proc_resp(device, ccb, is48bit, NULL); 1906249895Ssmh} 1907249895Ssmh 1908249895Ssmhstatic int 1909249895Ssmhatahpa_lock(struct cam_device *device, int retry_count, 1910249895Ssmh u_int32_t timeout, union ccb *ccb, int is48bit) 1911249895Ssmh{ 1912249895Ssmh int error; 1913249895Ssmh u_int cmd; 1914249895Ssmh u_int8_t protocol; 1915249895Ssmh 1916249895Ssmh protocol = AP_PROTO_NON_DATA; 1917249895Ssmh cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS; 1918249895Ssmh 1919249895Ssmh error = ata_do_cmd(device, 1920249895Ssmh ccb, 1921249895Ssmh retry_count, 1922251659Smav /*flags*/CAM_DIR_NONE, 1923249895Ssmh /*protocol*/protocol, 1924249895Ssmh /*ata_flags*/AP_FLAG_CHK_COND, 1925249895Ssmh /*tag_action*/MSG_SIMPLE_Q_TAG, 1926249895Ssmh /*command*/cmd, 1927249895Ssmh /*features*/ATA_HPA_FEAT_LOCK, 1928249895Ssmh /*lba*/0, 1929249895Ssmh /*sector_count*/0, 1930249895Ssmh /*data_ptr*/NULL, 1931249895Ssmh /*dxfer_len*/0, 1932249895Ssmh timeout ? timeout : 1000, 1933249895Ssmh is48bit); 1934249895Ssmh 1935249895Ssmh if (error) 1936249895Ssmh return (error); 1937249895Ssmh 1938249895Ssmh return atahpa_proc_resp(device, ccb, is48bit, NULL); 1939249895Ssmh} 1940249895Ssmh 1941249895Ssmhstatic int 1942249895Ssmhatahpa_unlock(struct cam_device *device, int retry_count, 1943249895Ssmh u_int32_t timeout, union ccb *ccb, 1944249895Ssmh int is48bit, struct ata_set_max_pwd *pwd) 1945249895Ssmh{ 1946249895Ssmh int error; 1947249895Ssmh u_int cmd; 1948249895Ssmh u_int8_t protocol; 1949249895Ssmh 1950249895Ssmh protocol = AP_PROTO_PIO_OUT; 1951249895Ssmh cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS; 1952249895Ssmh 1953249895Ssmh error = ata_do_cmd(device, 1954249895Ssmh ccb, 1955249895Ssmh retry_count, 1956249895Ssmh /*flags*/CAM_DIR_OUT, 1957249895Ssmh /*protocol*/protocol, 1958249895Ssmh /*ata_flags*/AP_FLAG_CHK_COND, 1959249895Ssmh /*tag_action*/MSG_SIMPLE_Q_TAG, 1960249895Ssmh /*command*/cmd, 1961249895Ssmh /*features*/ATA_HPA_FEAT_UNLOCK, 1962249895Ssmh /*lba*/0, 1963249895Ssmh /*sector_count*/0, 1964249895Ssmh /*data_ptr*/(u_int8_t*)pwd, 1965249895Ssmh /*dxfer_len*/sizeof(struct ata_set_max_pwd), 1966249895Ssmh timeout ? timeout : 1000, 1967249895Ssmh is48bit); 1968249895Ssmh 1969249895Ssmh if (error) 1970249895Ssmh return (error); 1971249895Ssmh 1972249895Ssmh return atahpa_proc_resp(device, ccb, is48bit, NULL); 1973249895Ssmh} 1974249895Ssmh 1975249895Ssmhstatic int 1976249895Ssmhatahpa_freeze_lock(struct cam_device *device, int retry_count, 1977249895Ssmh u_int32_t timeout, union ccb *ccb, int is48bit) 1978249895Ssmh{ 1979249895Ssmh int error; 1980249895Ssmh u_int cmd; 1981249895Ssmh u_int8_t protocol; 1982249895Ssmh 1983249895Ssmh protocol = AP_PROTO_NON_DATA; 1984249895Ssmh cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS; 1985249895Ssmh 1986249895Ssmh error = ata_do_cmd(device, 1987249895Ssmh ccb, 1988249895Ssmh retry_count, 1989251659Smav /*flags*/CAM_DIR_NONE, 1990249895Ssmh /*protocol*/protocol, 1991249895Ssmh /*ata_flags*/AP_FLAG_CHK_COND, 1992249895Ssmh /*tag_action*/MSG_SIMPLE_Q_TAG, 1993249895Ssmh /*command*/cmd, 1994249895Ssmh /*features*/ATA_HPA_FEAT_FREEZE, 1995249895Ssmh /*lba*/0, 1996249895Ssmh /*sector_count*/0, 1997249895Ssmh /*data_ptr*/NULL, 1998249895Ssmh /*dxfer_len*/0, 1999249895Ssmh timeout ? timeout : 1000, 2000249895Ssmh is48bit); 2001249895Ssmh 2002249895Ssmh if (error) 2003249895Ssmh return (error); 2004249895Ssmh 2005249895Ssmh return atahpa_proc_resp(device, ccb, is48bit, NULL); 2006249895Ssmh} 2007249895Ssmh 2008249895Ssmh 2009249895Ssmhstatic int 2010249115Ssmhata_do_identify(struct cam_device *device, int retry_count, int timeout, 2011249115Ssmh union ccb *ccb, struct ata_params** ident_bufp) 2012249115Ssmh{ 2013249115Ssmh struct ata_params *ident_buf; 2014249115Ssmh struct ccb_pathinq cpi; 2015249115Ssmh struct ccb_getdev cgd; 2016249115Ssmh u_int i, error; 2017249115Ssmh int16_t *ptr; 2018249115Ssmh u_int8_t command, retry_command; 2019249115Ssmh 2020249115Ssmh if (get_cpi(device, &cpi) != 0) { 2021249115Ssmh warnx("couldn't get CPI"); 2022249115Ssmh return (-1); 2023249115Ssmh } 2024249115Ssmh 2025249115Ssmh /* Neither PROTO_ATAPI or PROTO_SATAPM are used in cpi.protocol */ 2026249115Ssmh if (cpi.protocol == PROTO_ATA) { 2027249115Ssmh if (get_cgd(device, &cgd) != 0) { 2028249115Ssmh warnx("couldn't get CGD"); 2029249115Ssmh return (-1); 2030249115Ssmh } 2031249115Ssmh 2032249115Ssmh command = (cgd.protocol == PROTO_ATA) ? 2033249115Ssmh ATA_ATA_IDENTIFY : ATA_ATAPI_IDENTIFY; 2034249115Ssmh retry_command = 0; 2035249115Ssmh } else { 2036249115Ssmh /* We don't know which for sure so try both */ 2037249115Ssmh command = ATA_ATA_IDENTIFY; 2038249115Ssmh retry_command = ATA_ATAPI_IDENTIFY; 2039249115Ssmh } 2040249115Ssmh 2041249115Ssmh ptr = (uint16_t *)calloc(1, sizeof(struct ata_params)); 2042249115Ssmh if (ptr == NULL) { 2043249115Ssmh warnx("can't calloc memory for identify\n"); 2044249115Ssmh return (1); 2045249115Ssmh } 2046249115Ssmh 2047249115Ssmh error = ata_do_28bit_cmd(device, 2048249115Ssmh ccb, 2049249115Ssmh /*retries*/retry_count, 2050249115Ssmh /*flags*/CAM_DIR_IN, 2051249115Ssmh /*protocol*/AP_PROTO_PIO_IN, 2052249115Ssmh /*tag_action*/MSG_SIMPLE_Q_TAG, 2053249115Ssmh /*command*/command, 2054249115Ssmh /*features*/0, 2055249115Ssmh /*lba*/0, 2056249115Ssmh /*sector_count*/(u_int8_t)sizeof(struct ata_params), 2057249115Ssmh /*data_ptr*/(u_int8_t *)ptr, 2058249115Ssmh /*dxfer_len*/sizeof(struct ata_params), 2059249115Ssmh /*timeout*/timeout ? timeout : 30 * 1000, 2060249115Ssmh /*quiet*/1); 2061249115Ssmh 2062195534Sscottl if (error != 0) { 2063249115Ssmh if (retry_command == 0) { 2064249115Ssmh free(ptr); 2065249115Ssmh return (1); 2066249115Ssmh } 2067249115Ssmh error = ata_do_28bit_cmd(device, 2068249115Ssmh ccb, 2069249115Ssmh /*retries*/retry_count, 2070249115Ssmh /*flags*/CAM_DIR_IN, 2071249115Ssmh /*protocol*/AP_PROTO_PIO_IN, 2072249115Ssmh /*tag_action*/MSG_SIMPLE_Q_TAG, 2073249115Ssmh /*command*/retry_command, 2074249115Ssmh /*features*/0, 2075249115Ssmh /*lba*/0, 2076249115Ssmh /*sector_count*/(u_int8_t) 2077249115Ssmh sizeof(struct ata_params), 2078249115Ssmh /*data_ptr*/(u_int8_t *)ptr, 2079249115Ssmh /*dxfer_len*/sizeof(struct ata_params), 2080249115Ssmh /*timeout*/timeout ? timeout : 30 * 1000, 2081249115Ssmh /*quiet*/0); 2082249115Ssmh 2083249115Ssmh if (error != 0) { 2084249115Ssmh free(ptr); 2085249115Ssmh return (1); 2086249115Ssmh } 2087195534Sscottl } 2088195534Sscottl 2089249115Ssmh error = 1; 2090249115Ssmh for (i = 0; i < sizeof(struct ata_params) / 2; i++) { 2091195573Sscottl ptr[i] = le16toh(ptr[i]); 2092249115Ssmh if (ptr[i] != 0) 2093249115Ssmh error = 0; 2094249115Ssmh } 2095249115Ssmh 2096202694Smav if (arglist & CAM_ARG_VERBOSE) { 2097202694Smav fprintf(stdout, "%s%d: Raw identify data:\n", 2098202694Smav device->device_name, device->dev_unit_num); 2099249115Ssmh dump_data(ptr, sizeof(struct ata_params)); 2100202694Smav } 2101249115Ssmh 2102249115Ssmh /* check for invalid (all zero) response */ 2103249115Ssmh if (error != 0) { 2104249115Ssmh warnx("Invalid identify response detected"); 2105249115Ssmh free(ptr); 2106249115Ssmh return (error); 2107249115Ssmh } 2108249115Ssmh 2109195573Sscottl ident_buf = (struct ata_params *)ptr; 2110195534Sscottl if (strncmp(ident_buf->model, "FX", 2) && 2111195534Sscottl strncmp(ident_buf->model, "NEC", 3) && 2112195534Sscottl strncmp(ident_buf->model, "Pioneer", 7) && 2113195534Sscottl strncmp(ident_buf->model, "SHARP", 5)) { 2114195534Sscottl ata_bswap(ident_buf->model, sizeof(ident_buf->model)); 2115195534Sscottl ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); 2116195534Sscottl ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); 2117197545Smav ata_bswap(ident_buf->media_serial, sizeof(ident_buf->media_serial)); 2118195534Sscottl } 2119195534Sscottl ata_btrim(ident_buf->model, sizeof(ident_buf->model)); 2120195534Sscottl ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); 2121195534Sscottl ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); 2122195534Sscottl ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); 2123195534Sscottl ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); 2124195534Sscottl ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); 2125197545Smav ata_btrim(ident_buf->media_serial, sizeof(ident_buf->media_serial)); 2126197545Smav ata_bpack(ident_buf->media_serial, ident_buf->media_serial, 2127197545Smav sizeof(ident_buf->media_serial)); 2128195534Sscottl 2129249115Ssmh *ident_bufp = ident_buf; 2130249115Ssmh 2131249115Ssmh return (0); 2132249115Ssmh} 2133249115Ssmh 2134249115Ssmh 2135249115Ssmhstatic int 2136249115Ssmhataidentify(struct cam_device *device, int retry_count, int timeout) 2137249115Ssmh{ 2138249115Ssmh union ccb *ccb; 2139249115Ssmh struct ata_params *ident_buf; 2140249895Ssmh u_int64_t hpasize; 2141249115Ssmh 2142249115Ssmh if ((ccb = cam_getccb(device)) == NULL) { 2143249115Ssmh warnx("couldn't allocate CCB"); 2144249115Ssmh return (1); 2145249115Ssmh } 2146249115Ssmh 2147249115Ssmh if (ata_do_identify(device, retry_count, timeout, ccb, &ident_buf) != 0) { 2148249115Ssmh cam_freeccb(ccb); 2149249115Ssmh return (1); 2150249115Ssmh } 2151249115Ssmh 2152249895Ssmh if (ident_buf->support.command1 & ATA_SUPPORT_PROTECTED) { 2153249895Ssmh if (ata_read_native_max(device, retry_count, timeout, ccb, 2154249895Ssmh ident_buf, &hpasize) != 0) { 2155249895Ssmh cam_freeccb(ccb); 2156249895Ssmh return (1); 2157249895Ssmh } 2158249895Ssmh } else { 2159249895Ssmh hpasize = 0; 2160249895Ssmh } 2161249895Ssmh 2162249115Ssmh printf("%s%d: ", device->device_name, device->dev_unit_num); 2163195534Sscottl ata_print_ident(ident_buf); 2164198709Smav camxferrate(device); 2165195534Sscottl atacapprint(ident_buf); 2166249895Ssmh atahpa_print(ident_buf, hpasize, 0); 2167195534Sscottl 2168195534Sscottl free(ident_buf); 2169249115Ssmh cam_freeccb(ccb); 2170195534Sscottl 2171249115Ssmh return (0); 2172195534Sscottl} 217389471Sjoerg#endif /* MINIMALISTIC */ 217439214Sgibbs 2175249115Ssmh 2176249115Ssmh#ifndef MINIMALISTIC 2177249115Ssmhenum { 2178249115Ssmh ATA_SECURITY_ACTION_PRINT, 2179249115Ssmh ATA_SECURITY_ACTION_FREEZE, 2180249115Ssmh ATA_SECURITY_ACTION_UNLOCK, 2181249115Ssmh ATA_SECURITY_ACTION_DISABLE, 2182249115Ssmh ATA_SECURITY_ACTION_ERASE, 2183249115Ssmh ATA_SECURITY_ACTION_ERASE_ENHANCED, 2184249115Ssmh ATA_SECURITY_ACTION_SET_PASSWORD 2185249244Sed}; 2186249115Ssmh 2187249115Ssmhstatic void 2188249115Ssmhatasecurity_print_time(u_int16_t tw) 2189249115Ssmh{ 2190249115Ssmh 2191249115Ssmh if (tw == 0) 2192249115Ssmh printf("unspecified"); 2193249115Ssmh else if (tw >= 255) 2194249115Ssmh printf("> 508 min"); 2195249115Ssmh else 2196249115Ssmh printf("%i min", 2 * tw); 2197249115Ssmh} 2198249115Ssmh 2199249115Ssmhstatic u_int32_t 2200249115Ssmhatasecurity_erase_timeout_msecs(u_int16_t timeout) 2201249115Ssmh{ 2202249115Ssmh 2203249115Ssmh if (timeout == 0) 2204249115Ssmh return 2 * 3600 * 1000; /* default: two hours */ 2205249115Ssmh else if (timeout > 255) 2206249115Ssmh return (508 + 60) * 60 * 1000; /* spec says > 508 minutes */ 2207249115Ssmh 2208249115Ssmh return ((2 * timeout) + 5) * 60 * 1000; /* add a 5min margin */ 2209249115Ssmh} 2210249115Ssmh 2211249115Ssmh 2212249115Ssmhstatic void 2213249115Ssmhatasecurity_notify(u_int8_t command, struct ata_security_password *pwd) 2214249115Ssmh{ 2215249115Ssmh struct ata_cmd cmd; 2216249115Ssmh 2217249115Ssmh bzero(&cmd, sizeof(cmd)); 2218249115Ssmh cmd.command = command; 2219249115Ssmh printf("Issuing %s", ata_op_string(&cmd)); 2220249115Ssmh 2221249115Ssmh if (pwd != NULL) { 2222249115Ssmh char pass[sizeof(pwd->password)+1]; 2223249115Ssmh 2224249115Ssmh /* pwd->password may not be null terminated */ 2225249115Ssmh pass[sizeof(pwd->password)] = '\0'; 2226249115Ssmh strncpy(pass, pwd->password, sizeof(pwd->password)); 2227249115Ssmh printf(" password='%s', user='%s'", 2228249115Ssmh pass, 2229249115Ssmh (pwd->ctrl & ATA_SECURITY_PASSWORD_MASTER) ? 2230249115Ssmh "master" : "user"); 2231249115Ssmh 2232249115Ssmh if (command == ATA_SECURITY_SET_PASSWORD) { 2233249115Ssmh printf(", mode='%s'", 2234249115Ssmh (pwd->ctrl & ATA_SECURITY_LEVEL_MAXIMUM) ? 2235249115Ssmh "maximum" : "high"); 2236249115Ssmh } 2237249115Ssmh } 2238249115Ssmh 2239249115Ssmh printf("\n"); 2240249115Ssmh} 2241249115Ssmh 2242249115Ssmhstatic int 2243249115Ssmhatasecurity_freeze(struct cam_device *device, union ccb *ccb, 2244249115Ssmh int retry_count, u_int32_t timeout, int quiet) 2245249115Ssmh{ 2246249115Ssmh 2247249115Ssmh if (quiet == 0) 2248249115Ssmh atasecurity_notify(ATA_SECURITY_FREEZE_LOCK, NULL); 2249249115Ssmh 2250249115Ssmh return ata_do_28bit_cmd(device, 2251249115Ssmh ccb, 2252249115Ssmh retry_count, 2253249115Ssmh /*flags*/CAM_DIR_NONE, 2254249115Ssmh /*protocol*/AP_PROTO_NON_DATA, 2255249115Ssmh /*tag_action*/MSG_SIMPLE_Q_TAG, 2256249115Ssmh /*command*/ATA_SECURITY_FREEZE_LOCK, 2257249115Ssmh /*features*/0, 2258249115Ssmh /*lba*/0, 2259249115Ssmh /*sector_count*/0, 2260249115Ssmh /*data_ptr*/NULL, 2261249115Ssmh /*dxfer_len*/0, 2262249115Ssmh /*timeout*/timeout, 2263249115Ssmh /*quiet*/0); 2264249115Ssmh} 2265249115Ssmh 2266249115Ssmhstatic int 2267249115Ssmhatasecurity_unlock(struct cam_device *device, union ccb *ccb, 2268249115Ssmh int retry_count, u_int32_t timeout, 2269249115Ssmh struct ata_security_password *pwd, int quiet) 2270249115Ssmh{ 2271249115Ssmh 2272249115Ssmh if (quiet == 0) 2273249115Ssmh atasecurity_notify(ATA_SECURITY_UNLOCK, pwd); 2274249115Ssmh 2275249115Ssmh return ata_do_28bit_cmd(device, 2276249115Ssmh ccb, 2277249115Ssmh retry_count, 2278249115Ssmh /*flags*/CAM_DIR_OUT, 2279249115Ssmh /*protocol*/AP_PROTO_PIO_OUT, 2280249115Ssmh /*tag_action*/MSG_SIMPLE_Q_TAG, 2281249115Ssmh /*command*/ATA_SECURITY_UNLOCK, 2282249115Ssmh /*features*/0, 2283249115Ssmh /*lba*/0, 2284249115Ssmh /*sector_count*/0, 2285249115Ssmh /*data_ptr*/(u_int8_t *)pwd, 2286249115Ssmh /*dxfer_len*/sizeof(*pwd), 2287249115Ssmh /*timeout*/timeout, 2288249115Ssmh /*quiet*/0); 2289249115Ssmh} 2290249115Ssmh 2291249115Ssmhstatic int 2292249115Ssmhatasecurity_disable(struct cam_device *device, union ccb *ccb, 2293249115Ssmh int retry_count, u_int32_t timeout, 2294249115Ssmh struct ata_security_password *pwd, int quiet) 2295249115Ssmh{ 2296249115Ssmh 2297249115Ssmh if (quiet == 0) 2298249115Ssmh atasecurity_notify(ATA_SECURITY_DISABLE_PASSWORD, pwd); 2299249115Ssmh return ata_do_28bit_cmd(device, 2300249115Ssmh ccb, 2301249115Ssmh retry_count, 2302249115Ssmh /*flags*/CAM_DIR_OUT, 2303249115Ssmh /*protocol*/AP_PROTO_PIO_OUT, 2304249115Ssmh /*tag_action*/MSG_SIMPLE_Q_TAG, 2305249115Ssmh /*command*/ATA_SECURITY_DISABLE_PASSWORD, 2306249115Ssmh /*features*/0, 2307249115Ssmh /*lba*/0, 2308249115Ssmh /*sector_count*/0, 2309249115Ssmh /*data_ptr*/(u_int8_t *)pwd, 2310249115Ssmh /*dxfer_len*/sizeof(*pwd), 2311249115Ssmh /*timeout*/timeout, 2312249115Ssmh /*quiet*/0); 2313249115Ssmh} 2314249115Ssmh 2315249115Ssmh 2316249115Ssmhstatic int 2317249115Ssmhatasecurity_erase_confirm(struct cam_device *device, 2318249115Ssmh struct ata_params* ident_buf) 2319249115Ssmh{ 2320249115Ssmh 2321249115Ssmh printf("\nYou are about to ERASE ALL DATA from the following" 2322249115Ssmh " device:\n%s%d,%s%d: ", device->device_name, 2323249115Ssmh device->dev_unit_num, device->given_dev_name, 2324249115Ssmh device->given_unit_number); 2325249115Ssmh ata_print_ident(ident_buf); 2326249115Ssmh 2327249115Ssmh for(;;) { 2328249115Ssmh char str[50]; 2329249115Ssmh printf("\nAre you SURE you want to ERASE ALL DATA? (yes/no) "); 2330249115Ssmh 2331249115Ssmh if (fgets(str, sizeof(str), stdin) != NULL) { 2332249115Ssmh if (strncasecmp(str, "yes", 3) == 0) { 2333249115Ssmh return (1); 2334249115Ssmh } else if (strncasecmp(str, "no", 2) == 0) { 2335249115Ssmh return (0); 2336249115Ssmh } else { 2337249115Ssmh printf("Please answer \"yes\" or " 2338249115Ssmh "\"no\"\n"); 2339249115Ssmh } 2340249115Ssmh } 2341249115Ssmh } 2342249115Ssmh 2343249115Ssmh /* NOTREACHED */ 2344249115Ssmh return (0); 2345249115Ssmh} 2346249115Ssmh 2347249115Ssmhstatic int 2348249115Ssmhatasecurity_erase(struct cam_device *device, union ccb *ccb, 2349249115Ssmh int retry_count, u_int32_t timeout, 2350249115Ssmh u_int32_t erase_timeout, 2351249115Ssmh struct ata_security_password *pwd, int quiet) 2352249115Ssmh{ 2353249115Ssmh int error; 2354249115Ssmh 2355249115Ssmh if (quiet == 0) 2356249115Ssmh atasecurity_notify(ATA_SECURITY_ERASE_PREPARE, NULL); 2357249115Ssmh 2358249115Ssmh error = ata_do_28bit_cmd(device, 2359249115Ssmh ccb, 2360249115Ssmh retry_count, 2361249115Ssmh /*flags*/CAM_DIR_NONE, 2362249115Ssmh /*protocol*/AP_PROTO_NON_DATA, 2363249115Ssmh /*tag_action*/MSG_SIMPLE_Q_TAG, 2364249115Ssmh /*command*/ATA_SECURITY_ERASE_PREPARE, 2365249115Ssmh /*features*/0, 2366249115Ssmh /*lba*/0, 2367249115Ssmh /*sector_count*/0, 2368249115Ssmh /*data_ptr*/NULL, 2369249115Ssmh /*dxfer_len*/0, 2370249115Ssmh /*timeout*/timeout, 2371249115Ssmh /*quiet*/0); 2372249115Ssmh 2373249115Ssmh if (error != 0) 2374249115Ssmh return error; 2375249115Ssmh 2376249115Ssmh if (quiet == 0) 2377249115Ssmh atasecurity_notify(ATA_SECURITY_ERASE_UNIT, pwd); 2378249115Ssmh 2379249115Ssmh error = ata_do_28bit_cmd(device, 2380249115Ssmh ccb, 2381249115Ssmh retry_count, 2382249115Ssmh /*flags*/CAM_DIR_OUT, 2383249115Ssmh /*protocol*/AP_PROTO_PIO_OUT, 2384249115Ssmh /*tag_action*/MSG_SIMPLE_Q_TAG, 2385249115Ssmh /*command*/ATA_SECURITY_ERASE_UNIT, 2386249115Ssmh /*features*/0, 2387249115Ssmh /*lba*/0, 2388249115Ssmh /*sector_count*/0, 2389249115Ssmh /*data_ptr*/(u_int8_t *)pwd, 2390249115Ssmh /*dxfer_len*/sizeof(*pwd), 2391249115Ssmh /*timeout*/erase_timeout, 2392249115Ssmh /*quiet*/0); 2393249115Ssmh 2394249115Ssmh if (error == 0 && quiet == 0) 2395249115Ssmh printf("\nErase Complete\n"); 2396249115Ssmh 2397249115Ssmh return error; 2398249115Ssmh} 2399249115Ssmh 2400249115Ssmhstatic int 2401249115Ssmhatasecurity_set_password(struct cam_device *device, union ccb *ccb, 2402249115Ssmh int retry_count, u_int32_t timeout, 2403249115Ssmh struct ata_security_password *pwd, int quiet) 2404249115Ssmh{ 2405249115Ssmh 2406249115Ssmh if (quiet == 0) 2407249115Ssmh atasecurity_notify(ATA_SECURITY_SET_PASSWORD, pwd); 2408249115Ssmh 2409249115Ssmh return ata_do_28bit_cmd(device, 2410249115Ssmh ccb, 2411249115Ssmh retry_count, 2412249115Ssmh /*flags*/CAM_DIR_OUT, 2413249115Ssmh /*protocol*/AP_PROTO_PIO_OUT, 2414249115Ssmh /*tag_action*/MSG_SIMPLE_Q_TAG, 2415249115Ssmh /*command*/ATA_SECURITY_SET_PASSWORD, 2416249115Ssmh /*features*/0, 2417249115Ssmh /*lba*/0, 2418249115Ssmh /*sector_count*/0, 2419249115Ssmh /*data_ptr*/(u_int8_t *)pwd, 2420249115Ssmh /*dxfer_len*/sizeof(*pwd), 2421249115Ssmh /*timeout*/timeout, 2422249115Ssmh /*quiet*/0); 2423249115Ssmh} 2424249115Ssmh 2425249115Ssmhstatic void 2426249115Ssmhatasecurity_print(struct ata_params *parm) 2427249115Ssmh{ 2428249115Ssmh 2429249115Ssmh printf("\nSecurity Option Value\n"); 2430249115Ssmh if (arglist & CAM_ARG_VERBOSE) { 2431249115Ssmh printf("status %04x\n", 2432249115Ssmh parm->security_status); 2433249115Ssmh } 2434249115Ssmh printf("supported %s\n", 2435249115Ssmh parm->security_status & ATA_SECURITY_SUPPORTED ? "yes" : "no"); 2436249115Ssmh if (!(parm->security_status & ATA_SECURITY_SUPPORTED)) 2437249115Ssmh return; 2438249115Ssmh printf("enabled %s\n", 2439249115Ssmh parm->security_status & ATA_SECURITY_ENABLED ? "yes" : "no"); 2440249115Ssmh printf("drive locked %s\n", 2441249115Ssmh parm->security_status & ATA_SECURITY_LOCKED ? "yes" : "no"); 2442249115Ssmh printf("security config frozen %s\n", 2443249115Ssmh parm->security_status & ATA_SECURITY_FROZEN ? "yes" : "no"); 2444249115Ssmh printf("count expired %s\n", 2445249115Ssmh parm->security_status & ATA_SECURITY_COUNT_EXP ? "yes" : "no"); 2446249115Ssmh printf("security level %s\n", 2447249115Ssmh parm->security_status & ATA_SECURITY_LEVEL ? "maximum" : "high"); 2448249115Ssmh printf("enhanced erase supported %s\n", 2449249115Ssmh parm->security_status & ATA_SECURITY_ENH_SUPP ? "yes" : "no"); 2450249115Ssmh printf("erase time "); 2451249115Ssmh atasecurity_print_time(parm->erase_time); 2452249115Ssmh printf("\n"); 2453249115Ssmh printf("enhanced erase time "); 2454249115Ssmh atasecurity_print_time(parm->enhanced_erase_time); 2455249115Ssmh printf("\n"); 2456249115Ssmh printf("master password rev %04x%s\n", 2457249115Ssmh parm->master_passwd_revision, 2458249115Ssmh parm->master_passwd_revision == 0x0000 || 2459249115Ssmh parm->master_passwd_revision == 0xFFFF ? " (unsupported)" : ""); 2460249115Ssmh} 2461249115Ssmh 246246938Sken/* 2463249115Ssmh * Validates and copies the password in optarg to the passed buffer. 2464249115Ssmh * If the password in optarg is the same length as the buffer then 2465249115Ssmh * the data will still be copied but no null termination will occur. 2466249115Ssmh */ 2467249115Ssmhstatic int 2468249115Ssmhata_getpwd(u_int8_t *passwd, int max, char opt) 2469249115Ssmh{ 2470249115Ssmh int len; 2471249115Ssmh 2472249115Ssmh len = strlen(optarg); 2473249115Ssmh if (len > max) { 2474249115Ssmh warnx("-%c password is too long", opt); 2475249115Ssmh return (1); 2476249115Ssmh } else if (len == 0) { 2477249115Ssmh warnx("-%c password is missing", opt); 2478249115Ssmh return (1); 2479249115Ssmh } else if (optarg[0] == '-'){ 2480249115Ssmh warnx("-%c password starts with '-' (generic arg?)", opt); 2481249115Ssmh return (1); 2482249115Ssmh } else if (strlen(passwd) != 0 && strcmp(passwd, optarg) != 0) { 2483249115Ssmh warnx("-%c password conflicts with existing password from -%c", 2484249115Ssmh opt, pwd_opt); 2485249115Ssmh return (1); 2486249115Ssmh } 2487249115Ssmh 2488249115Ssmh /* Callers pass in a buffer which does NOT need to be terminated */ 2489249115Ssmh strncpy(passwd, optarg, max); 2490249115Ssmh pwd_opt = opt; 2491249115Ssmh 2492249115Ssmh return (0); 2493249115Ssmh} 2494249115Ssmh 2495249895Ssmhenum { 2496249895Ssmh ATA_HPA_ACTION_PRINT, 2497249895Ssmh ATA_HPA_ACTION_SET_MAX, 2498249895Ssmh ATA_HPA_ACTION_SET_PWD, 2499249895Ssmh ATA_HPA_ACTION_LOCK, 2500249895Ssmh ATA_HPA_ACTION_UNLOCK, 2501249895Ssmh ATA_HPA_ACTION_FREEZE_LOCK 2502249895Ssmh}; 2503249895Ssmh 2504249115Ssmhstatic int 2505249895Ssmhatahpa_set_confirm(struct cam_device *device, struct ata_params* ident_buf, 2506249895Ssmh u_int64_t maxsize, int persist) 2507249895Ssmh{ 2508249895Ssmh printf("\nYou are about to configure HPA to limit the user accessible\n" 2509249895Ssmh "sectors to %ju %s on the device:\n%s%d,%s%d: ", maxsize, 2510249895Ssmh persist ? "persistently" : "temporarily", 2511249895Ssmh device->device_name, device->dev_unit_num, 2512249895Ssmh device->given_dev_name, device->given_unit_number); 2513249895Ssmh ata_print_ident(ident_buf); 2514249895Ssmh 2515249895Ssmh for(;;) { 2516249895Ssmh char str[50]; 2517249895Ssmh printf("\nAre you SURE you want to configure HPA? (yes/no) "); 2518249895Ssmh 2519249895Ssmh if (NULL != fgets(str, sizeof(str), stdin)) { 2520249895Ssmh if (0 == strncasecmp(str, "yes", 3)) { 2521249895Ssmh return (1); 2522249895Ssmh } else if (0 == strncasecmp(str, "no", 2)) { 2523249895Ssmh return (0); 2524249895Ssmh } else { 2525249895Ssmh printf("Please answer \"yes\" or " 2526249895Ssmh "\"no\"\n"); 2527249895Ssmh } 2528249895Ssmh } 2529249895Ssmh } 2530249895Ssmh 2531249895Ssmh /* NOTREACHED */ 2532249895Ssmh return (0); 2533249895Ssmh} 2534249895Ssmh 2535249895Ssmhstatic int 2536249895Ssmhatahpa(struct cam_device *device, int retry_count, int timeout, 2537249895Ssmh int argc, char **argv, char *combinedopt) 2538249895Ssmh{ 2539249895Ssmh union ccb *ccb; 2540249895Ssmh struct ata_params *ident_buf; 2541249895Ssmh struct ccb_getdev cgd; 2542249895Ssmh struct ata_set_max_pwd pwd; 2543249895Ssmh int error, confirm, quiet, c, action, actions, setpwd, persist; 2544249895Ssmh int security, is48bit, pwdsize; 2545249895Ssmh u_int64_t hpasize, maxsize; 2546249895Ssmh 2547249895Ssmh actions = 0; 2548249895Ssmh setpwd = 0; 2549249895Ssmh confirm = 0; 2550249895Ssmh quiet = 0; 2551249895Ssmh maxsize = 0; 2552249895Ssmh persist = 0; 2553249895Ssmh security = 0; 2554249895Ssmh 2555249895Ssmh memset(&pwd, 0, sizeof(pwd)); 2556249895Ssmh 2557249895Ssmh /* default action is to print hpa information */ 2558249895Ssmh action = ATA_HPA_ACTION_PRINT; 2559249895Ssmh pwdsize = sizeof(pwd.password); 2560249895Ssmh 2561249895Ssmh while ((c = getopt(argc, argv, combinedopt)) != -1) { 2562249895Ssmh switch(c){ 2563249895Ssmh case 's': 2564249895Ssmh action = ATA_HPA_ACTION_SET_MAX; 2565249895Ssmh maxsize = strtoumax(optarg, NULL, 0); 2566249895Ssmh actions++; 2567249895Ssmh break; 2568249895Ssmh 2569249895Ssmh case 'p': 2570249895Ssmh if (ata_getpwd(pwd.password, pwdsize, c) != 0) 2571249895Ssmh return (1); 2572249895Ssmh action = ATA_HPA_ACTION_SET_PWD; 2573249895Ssmh security = 1; 2574249895Ssmh actions++; 2575249895Ssmh break; 2576249895Ssmh 2577249895Ssmh case 'l': 2578249895Ssmh action = ATA_HPA_ACTION_LOCK; 2579249895Ssmh security = 1; 2580249895Ssmh actions++; 2581249895Ssmh break; 2582249895Ssmh 2583249895Ssmh case 'U': 2584249895Ssmh if (ata_getpwd(pwd.password, pwdsize, c) != 0) 2585249895Ssmh return (1); 2586249895Ssmh action = ATA_HPA_ACTION_UNLOCK; 2587249895Ssmh security = 1; 2588249895Ssmh actions++; 2589249895Ssmh break; 2590249895Ssmh 2591249895Ssmh case 'f': 2592249895Ssmh action = ATA_HPA_ACTION_FREEZE_LOCK; 2593249895Ssmh security = 1; 2594249895Ssmh actions++; 2595249895Ssmh break; 2596249895Ssmh 2597249895Ssmh case 'P': 2598249895Ssmh persist = 1; 2599249895Ssmh break; 2600249895Ssmh 2601249895Ssmh case 'y': 2602249895Ssmh confirm++; 2603249895Ssmh break; 2604249895Ssmh 2605249895Ssmh case 'q': 2606249895Ssmh quiet++; 2607249895Ssmh break; 2608249895Ssmh } 2609249895Ssmh } 2610249895Ssmh 2611249895Ssmh if (actions > 1) { 2612249895Ssmh warnx("too many hpa actions specified"); 2613249895Ssmh return (1); 2614249895Ssmh } 2615249895Ssmh 2616249895Ssmh if (get_cgd(device, &cgd) != 0) { 2617249895Ssmh warnx("couldn't get CGD"); 2618249895Ssmh return (1); 2619249895Ssmh } 2620249895Ssmh 2621249895Ssmh ccb = cam_getccb(device); 2622249895Ssmh if (ccb == NULL) { 2623249895Ssmh warnx("couldn't allocate CCB"); 2624249895Ssmh return (1); 2625249895Ssmh } 2626249895Ssmh 2627249895Ssmh error = ata_do_identify(device, retry_count, timeout, ccb, &ident_buf); 2628249895Ssmh if (error != 0) { 2629249895Ssmh cam_freeccb(ccb); 2630249895Ssmh return (1); 2631249895Ssmh } 2632249895Ssmh 2633249895Ssmh if (quiet == 0) { 2634249895Ssmh printf("%s%d: ", device->device_name, device->dev_unit_num); 2635249895Ssmh ata_print_ident(ident_buf); 2636249895Ssmh camxferrate(device); 2637249895Ssmh } 2638249895Ssmh 2639249895Ssmh if (action == ATA_HPA_ACTION_PRINT) { 2640249895Ssmh error = ata_read_native_max(device, retry_count, timeout, ccb, 2641249895Ssmh ident_buf, &hpasize); 2642249895Ssmh if (error == 0) 2643249895Ssmh atahpa_print(ident_buf, hpasize, 1); 2644249895Ssmh 2645249895Ssmh cam_freeccb(ccb); 2646249895Ssmh free(ident_buf); 2647249895Ssmh return (error); 2648249895Ssmh } 2649249895Ssmh 2650249895Ssmh if (!(ident_buf->support.command1 & ATA_SUPPORT_PROTECTED)) { 2651249895Ssmh warnx("HPA is not supported by this device"); 2652249895Ssmh cam_freeccb(ccb); 2653249895Ssmh free(ident_buf); 2654249895Ssmh return (1); 2655249895Ssmh } 2656249895Ssmh 2657249895Ssmh if (security && !(ident_buf->support.command1 & ATA_SUPPORT_MAXSECURITY)) { 2658249895Ssmh warnx("HPA Security is not supported by this device"); 2659249895Ssmh cam_freeccb(ccb); 2660249895Ssmh free(ident_buf); 2661249895Ssmh return (1); 2662249895Ssmh } 2663249895Ssmh 2664249895Ssmh is48bit = ident_buf->support.command2 & ATA_SUPPORT_ADDRESS48; 2665249895Ssmh 2666249895Ssmh /* 2667249895Ssmh * The ATA spec requires: 2668249895Ssmh * 1. Read native max addr is called directly before set max addr 2669249895Ssmh * 2. Read native max addr is NOT called before any other set max call 2670249895Ssmh */ 2671249895Ssmh switch(action) { 2672249895Ssmh case ATA_HPA_ACTION_SET_MAX: 2673249895Ssmh if (confirm == 0 && 2674249895Ssmh atahpa_set_confirm(device, ident_buf, maxsize, 2675249895Ssmh persist) == 0) { 2676249895Ssmh cam_freeccb(ccb); 2677249895Ssmh free(ident_buf); 2678249895Ssmh return (1); 2679249895Ssmh } 2680249895Ssmh 2681249895Ssmh error = ata_read_native_max(device, retry_count, timeout, 2682249895Ssmh ccb, ident_buf, &hpasize); 2683249895Ssmh if (error == 0) { 2684249895Ssmh error = atahpa_set_max(device, retry_count, timeout, 2685249895Ssmh ccb, is48bit, maxsize, persist); 2686249895Ssmh if (error == 0) { 2687249895Ssmh /* redo identify to get new lba values */ 2688249895Ssmh error = ata_do_identify(device, retry_count, 2689249895Ssmh timeout, ccb, 2690249895Ssmh &ident_buf); 2691249895Ssmh atahpa_print(ident_buf, hpasize, 1); 2692249895Ssmh } 2693249895Ssmh } 2694249895Ssmh break; 2695249895Ssmh 2696249895Ssmh case ATA_HPA_ACTION_SET_PWD: 2697249895Ssmh error = atahpa_password(device, retry_count, timeout, 2698249895Ssmh ccb, is48bit, &pwd); 2699249895Ssmh if (error == 0) 2700249895Ssmh printf("HPA password has been set\n"); 2701249895Ssmh break; 2702249895Ssmh 2703249895Ssmh case ATA_HPA_ACTION_LOCK: 2704249895Ssmh error = atahpa_lock(device, retry_count, timeout, 2705249895Ssmh ccb, is48bit); 2706249895Ssmh if (error == 0) 2707249895Ssmh printf("HPA has been locked\n"); 2708249895Ssmh break; 2709249895Ssmh 2710249895Ssmh case ATA_HPA_ACTION_UNLOCK: 2711249895Ssmh error = atahpa_unlock(device, retry_count, timeout, 2712249895Ssmh ccb, is48bit, &pwd); 2713249895Ssmh if (error == 0) 2714249895Ssmh printf("HPA has been unlocked\n"); 2715249895Ssmh break; 2716249895Ssmh 2717249895Ssmh case ATA_HPA_ACTION_FREEZE_LOCK: 2718249895Ssmh error = atahpa_freeze_lock(device, retry_count, timeout, 2719249895Ssmh ccb, is48bit); 2720249895Ssmh if (error == 0) 2721249895Ssmh printf("HPA has been frozen\n"); 2722249895Ssmh break; 2723249895Ssmh 2724249895Ssmh default: 2725249895Ssmh errx(1, "Option currently not supported"); 2726249895Ssmh } 2727249895Ssmh 2728249895Ssmh cam_freeccb(ccb); 2729249895Ssmh free(ident_buf); 2730249895Ssmh 2731249895Ssmh return (error); 2732249895Ssmh} 2733249895Ssmh 2734249895Ssmhstatic int 2735249115Ssmhatasecurity(struct cam_device *device, int retry_count, int timeout, 2736249115Ssmh int argc, char **argv, char *combinedopt) 2737249115Ssmh{ 2738249115Ssmh union ccb *ccb; 2739249115Ssmh struct ata_params *ident_buf; 2740249115Ssmh int error, confirm, quiet, c, action, actions, setpwd; 2741249115Ssmh int security_enabled, erase_timeout, pwdsize; 2742249115Ssmh struct ata_security_password pwd; 2743249115Ssmh 2744249115Ssmh actions = 0; 2745249115Ssmh setpwd = 0; 2746249115Ssmh erase_timeout = 0; 2747249115Ssmh confirm = 0; 2748249115Ssmh quiet = 0; 2749249115Ssmh 2750249115Ssmh memset(&pwd, 0, sizeof(pwd)); 2751249115Ssmh 2752249115Ssmh /* default action is to print security information */ 2753249115Ssmh action = ATA_SECURITY_ACTION_PRINT; 2754249115Ssmh 2755249115Ssmh /* user is master by default as its safer that way */ 2756249115Ssmh pwd.ctrl |= ATA_SECURITY_PASSWORD_MASTER; 2757249115Ssmh pwdsize = sizeof(pwd.password); 2758249115Ssmh 2759249115Ssmh while ((c = getopt(argc, argv, combinedopt)) != -1) { 2760249115Ssmh switch(c){ 2761249115Ssmh case 'f': 2762249115Ssmh action = ATA_SECURITY_ACTION_FREEZE; 2763249115Ssmh actions++; 2764249115Ssmh break; 2765249115Ssmh 2766249115Ssmh case 'U': 2767249115Ssmh if (strcasecmp(optarg, "user") == 0) { 2768249115Ssmh pwd.ctrl |= ATA_SECURITY_PASSWORD_USER; 2769249115Ssmh pwd.ctrl &= ~ATA_SECURITY_PASSWORD_MASTER; 2770256133Smarkj } else if (strcasecmp(optarg, "master") == 0) { 2771249115Ssmh pwd.ctrl |= ATA_SECURITY_PASSWORD_MASTER; 2772249115Ssmh pwd.ctrl &= ~ATA_SECURITY_PASSWORD_USER; 2773249115Ssmh } else { 2774249115Ssmh warnx("-U argument '%s' is invalid (must be " 2775249115Ssmh "'user' or 'master')", optarg); 2776249115Ssmh return (1); 2777249115Ssmh } 2778249115Ssmh break; 2779249115Ssmh 2780249115Ssmh case 'l': 2781249115Ssmh if (strcasecmp(optarg, "high") == 0) { 2782249115Ssmh pwd.ctrl |= ATA_SECURITY_LEVEL_HIGH; 2783249115Ssmh pwd.ctrl &= ~ATA_SECURITY_LEVEL_MAXIMUM; 2784249115Ssmh } else if (strcasecmp(optarg, "maximum") == 0) { 2785249115Ssmh pwd.ctrl |= ATA_SECURITY_LEVEL_MAXIMUM; 2786249115Ssmh pwd.ctrl &= ~ATA_SECURITY_LEVEL_HIGH; 2787249115Ssmh } else { 2788249115Ssmh warnx("-l argument '%s' is unknown (must be " 2789249115Ssmh "'high' or 'maximum')", optarg); 2790249115Ssmh return (1); 2791249115Ssmh } 2792249115Ssmh break; 2793249115Ssmh 2794249115Ssmh case 'k': 2795249115Ssmh if (ata_getpwd(pwd.password, pwdsize, c) != 0) 2796249115Ssmh return (1); 2797249115Ssmh action = ATA_SECURITY_ACTION_UNLOCK; 2798249115Ssmh actions++; 2799249115Ssmh break; 2800249115Ssmh 2801249115Ssmh case 'd': 2802249115Ssmh if (ata_getpwd(pwd.password, pwdsize, c) != 0) 2803249115Ssmh return (1); 2804249115Ssmh action = ATA_SECURITY_ACTION_DISABLE; 2805249115Ssmh actions++; 2806249115Ssmh break; 2807249115Ssmh 2808249115Ssmh case 'e': 2809249115Ssmh if (ata_getpwd(pwd.password, pwdsize, c) != 0) 2810249115Ssmh return (1); 2811249115Ssmh action = ATA_SECURITY_ACTION_ERASE; 2812249115Ssmh actions++; 2813249115Ssmh break; 2814249115Ssmh 2815249115Ssmh case 'h': 2816249115Ssmh if (ata_getpwd(pwd.password, pwdsize, c) != 0) 2817249115Ssmh return (1); 2818249115Ssmh pwd.ctrl |= ATA_SECURITY_ERASE_ENHANCED; 2819249115Ssmh action = ATA_SECURITY_ACTION_ERASE_ENHANCED; 2820249115Ssmh actions++; 2821249115Ssmh break; 2822249115Ssmh 2823249115Ssmh case 's': 2824249115Ssmh if (ata_getpwd(pwd.password, pwdsize, c) != 0) 2825249115Ssmh return (1); 2826249115Ssmh setpwd = 1; 2827249115Ssmh if (action == ATA_SECURITY_ACTION_PRINT) 2828249115Ssmh action = ATA_SECURITY_ACTION_SET_PASSWORD; 2829249115Ssmh /* 2830249115Ssmh * Don't increment action as this can be combined 2831249115Ssmh * with other actions. 2832249115Ssmh */ 2833249115Ssmh break; 2834249115Ssmh 2835249115Ssmh case 'y': 2836249115Ssmh confirm++; 2837249115Ssmh break; 2838249115Ssmh 2839249115Ssmh case 'q': 2840249115Ssmh quiet++; 2841249115Ssmh break; 2842249115Ssmh 2843249115Ssmh case 'T': 2844249115Ssmh erase_timeout = atoi(optarg) * 1000; 2845249115Ssmh break; 2846249115Ssmh } 2847249115Ssmh } 2848249115Ssmh 2849249115Ssmh if (actions > 1) { 2850249115Ssmh warnx("too many security actions specified"); 2851249115Ssmh return (1); 2852249115Ssmh } 2853249115Ssmh 2854249115Ssmh if ((ccb = cam_getccb(device)) == NULL) { 2855249115Ssmh warnx("couldn't allocate CCB"); 2856249115Ssmh return (1); 2857249115Ssmh } 2858249115Ssmh 2859249115Ssmh error = ata_do_identify(device, retry_count, timeout, ccb, &ident_buf); 2860249115Ssmh if (error != 0) { 2861249115Ssmh cam_freeccb(ccb); 2862249115Ssmh return (1); 2863249115Ssmh } 2864249115Ssmh 2865249115Ssmh if (quiet == 0) { 2866249115Ssmh printf("%s%d: ", device->device_name, device->dev_unit_num); 2867249115Ssmh ata_print_ident(ident_buf); 2868249115Ssmh camxferrate(device); 2869249115Ssmh } 2870249115Ssmh 2871249115Ssmh if (action == ATA_SECURITY_ACTION_PRINT) { 2872249115Ssmh atasecurity_print(ident_buf); 2873249115Ssmh free(ident_buf); 2874249115Ssmh cam_freeccb(ccb); 2875249115Ssmh return (0); 2876249115Ssmh } 2877249115Ssmh 2878249115Ssmh if ((ident_buf->support.command1 & ATA_SUPPORT_SECURITY) == 0) { 2879249115Ssmh warnx("Security not supported"); 2880249115Ssmh free(ident_buf); 2881249115Ssmh cam_freeccb(ccb); 2882249115Ssmh return (1); 2883249115Ssmh } 2884249115Ssmh 2885249115Ssmh /* default timeout 15 seconds the same as linux hdparm */ 2886249115Ssmh timeout = timeout ? timeout : 15 * 1000; 2887249115Ssmh 2888249115Ssmh security_enabled = ident_buf->security_status & ATA_SECURITY_ENABLED; 2889249115Ssmh 2890249115Ssmh /* first set the password if requested */ 2891249115Ssmh if (setpwd == 1) { 2892249115Ssmh /* confirm we can erase before setting the password if erasing */ 2893249115Ssmh if (confirm == 0 && 2894249115Ssmh (action == ATA_SECURITY_ACTION_ERASE_ENHANCED || 2895249115Ssmh action == ATA_SECURITY_ACTION_ERASE) && 2896249115Ssmh atasecurity_erase_confirm(device, ident_buf) == 0) { 2897249115Ssmh cam_freeccb(ccb); 2898249115Ssmh free(ident_buf); 2899249115Ssmh return (error); 2900249115Ssmh } 2901249115Ssmh 2902249115Ssmh if (pwd.ctrl & ATA_SECURITY_PASSWORD_MASTER) { 2903249115Ssmh pwd.revision = ident_buf->master_passwd_revision; 2904249115Ssmh if (pwd.revision != 0 && pwd.revision != 0xfff && 2905249115Ssmh --pwd.revision == 0) { 2906249115Ssmh pwd.revision = 0xfffe; 2907249115Ssmh } 2908249115Ssmh } 2909249115Ssmh error = atasecurity_set_password(device, ccb, retry_count, 2910249115Ssmh timeout, &pwd, quiet); 2911249115Ssmh if (error != 0) { 2912249115Ssmh cam_freeccb(ccb); 2913249115Ssmh free(ident_buf); 2914249115Ssmh return (error); 2915249115Ssmh } 2916249115Ssmh security_enabled = 1; 2917249115Ssmh } 2918249115Ssmh 2919249115Ssmh switch(action) { 2920249115Ssmh case ATA_SECURITY_ACTION_FREEZE: 2921249115Ssmh error = atasecurity_freeze(device, ccb, retry_count, 2922249115Ssmh timeout, quiet); 2923249115Ssmh break; 2924249115Ssmh 2925249115Ssmh case ATA_SECURITY_ACTION_UNLOCK: 2926249115Ssmh if (security_enabled) { 2927249115Ssmh if (ident_buf->security_status & ATA_SECURITY_LOCKED) { 2928249115Ssmh error = atasecurity_unlock(device, ccb, 2929249115Ssmh retry_count, timeout, &pwd, quiet); 2930249115Ssmh } else { 2931249115Ssmh warnx("Can't unlock, drive is not locked"); 2932249115Ssmh error = 1; 2933249115Ssmh } 2934249115Ssmh } else { 2935249115Ssmh warnx("Can't unlock, security is disabled"); 2936249115Ssmh error = 1; 2937249115Ssmh } 2938249115Ssmh break; 2939249115Ssmh 2940249115Ssmh case ATA_SECURITY_ACTION_DISABLE: 2941249115Ssmh if (security_enabled) { 2942249115Ssmh /* First unlock the drive if its locked */ 2943249115Ssmh if (ident_buf->security_status & ATA_SECURITY_LOCKED) { 2944249115Ssmh error = atasecurity_unlock(device, ccb, 2945249115Ssmh retry_count, 2946249115Ssmh timeout, 2947249115Ssmh &pwd, 2948249115Ssmh quiet); 2949249115Ssmh } 2950249115Ssmh 2951249115Ssmh if (error == 0) { 2952249115Ssmh error = atasecurity_disable(device, 2953249115Ssmh ccb, 2954249115Ssmh retry_count, 2955249115Ssmh timeout, 2956249115Ssmh &pwd, 2957249115Ssmh quiet); 2958249115Ssmh } 2959249115Ssmh } else { 2960249115Ssmh warnx("Can't disable security (already disabled)"); 2961249115Ssmh error = 1; 2962249115Ssmh } 2963249115Ssmh break; 2964249115Ssmh 2965249115Ssmh case ATA_SECURITY_ACTION_ERASE: 2966249115Ssmh if (security_enabled) { 2967249115Ssmh if (erase_timeout == 0) { 2968249115Ssmh erase_timeout = atasecurity_erase_timeout_msecs( 2969249115Ssmh ident_buf->erase_time); 2970249115Ssmh } 2971249115Ssmh 2972249115Ssmh error = atasecurity_erase(device, ccb, retry_count, 2973249115Ssmh timeout, erase_timeout, &pwd, 2974249115Ssmh quiet); 2975249115Ssmh } else { 2976249115Ssmh warnx("Can't secure erase (security is disabled)"); 2977249115Ssmh error = 1; 2978249115Ssmh } 2979249115Ssmh break; 2980249115Ssmh 2981249115Ssmh case ATA_SECURITY_ACTION_ERASE_ENHANCED: 2982249115Ssmh if (security_enabled) { 2983249115Ssmh if (ident_buf->security_status & ATA_SECURITY_ENH_SUPP) { 2984249115Ssmh if (erase_timeout == 0) { 2985249115Ssmh erase_timeout = 2986249115Ssmh atasecurity_erase_timeout_msecs( 2987249115Ssmh ident_buf->enhanced_erase_time); 2988249115Ssmh } 2989249115Ssmh 2990249115Ssmh error = atasecurity_erase(device, ccb, 2991249115Ssmh retry_count, timeout, 2992249115Ssmh erase_timeout, &pwd, 2993249115Ssmh quiet); 2994249115Ssmh } else { 2995249115Ssmh warnx("Enhanced erase is not supported"); 2996249115Ssmh error = 1; 2997249115Ssmh } 2998249115Ssmh } else { 2999249115Ssmh warnx("Can't secure erase (enhanced), " 3000249115Ssmh "(security is disabled)"); 3001249115Ssmh error = 1; 3002249115Ssmh } 3003249115Ssmh break; 3004249115Ssmh } 3005249115Ssmh 3006249115Ssmh cam_freeccb(ccb); 3007249115Ssmh free(ident_buf); 3008249115Ssmh 3009249115Ssmh return (error); 3010249115Ssmh} 3011249115Ssmh#endif /* MINIMALISTIC */ 3012249115Ssmh 3013249115Ssmh/* 301446938Sken * Parse out a bus, or a bus, target and lun in the following 301546938Sken * format: 301646938Sken * bus 301746938Sken * bus:target 301846938Sken * bus:target:lun 301946938Sken * 302046938Sken * Returns the number of parsed components, or 0. 302146938Sken */ 302239214Sgibbsstatic int 3023260509Smavparse_btl(char *tstr, path_id_t *bus, target_id_t *target, lun_id_t *lun, 3024260509Smav cam_argmask *arglst) 302546938Sken{ 302646938Sken char *tmpstr; 302746938Sken int convs = 0; 302846938Sken 302946938Sken while (isspace(*tstr) && (*tstr != '\0')) 303046938Sken tstr++; 303146938Sken 303246938Sken tmpstr = (char *)strtok(tstr, ":"); 303346938Sken if ((tmpstr != NULL) && (*tmpstr != '\0')) { 303446938Sken *bus = strtol(tmpstr, NULL, 0); 3035118478Sjohan *arglst |= CAM_ARG_BUS; 303646938Sken convs++; 303746938Sken tmpstr = (char *)strtok(NULL, ":"); 303846938Sken if ((tmpstr != NULL) && (*tmpstr != '\0')) { 303946938Sken *target = strtol(tmpstr, NULL, 0); 3040118478Sjohan *arglst |= CAM_ARG_TARGET; 304146938Sken convs++; 304246938Sken tmpstr = (char *)strtok(NULL, ":"); 304346938Sken if ((tmpstr != NULL) && (*tmpstr != '\0')) { 304446938Sken *lun = strtol(tmpstr, NULL, 0); 3045118478Sjohan *arglst |= CAM_ARG_LUN; 304646938Sken convs++; 304746938Sken } 304846938Sken } 304946938Sken } 305046938Sken 305146938Sken return convs; 305246938Sken} 305346938Sken 305446938Skenstatic int 305541962Smjacobdorescan_or_reset(int argc, char **argv, int rescan) 305639214Sgibbs{ 305769254Skris static const char must[] = 305889515Sken "you must specify \"all\", a bus, or a bus:target:lun to %s"; 305946938Sken int rv, error = 0; 3060260509Smav path_id_t bus = CAM_BUS_WILDCARD; 3061260509Smav target_id_t target = CAM_TARGET_WILDCARD; 3062260509Smav lun_id_t lun = CAM_LUN_WILDCARD; 306389515Sken char *tstr; 306439214Sgibbs 306539214Sgibbs if (argc < 3) { 306641962Smjacob warnx(must, rescan? "rescan" : "reset"); 306739214Sgibbs return(1); 306839214Sgibbs } 306989515Sken 307089515Sken tstr = argv[optind]; 307189515Sken while (isspace(*tstr) && (*tstr != '\0')) 307289515Sken tstr++; 307389515Sken if (strncasecmp(tstr, "all", strlen("all")) == 0) 307489515Sken arglist |= CAM_ARG_BUS; 307589515Sken else { 307689515Sken rv = parse_btl(argv[optind], &bus, &target, &lun, &arglist); 307789515Sken if (rv != 1 && rv != 3) { 307889515Sken warnx(must, rescan? "rescan" : "reset"); 307989515Sken return(1); 308089515Sken } 308139214Sgibbs } 308239214Sgibbs 308346938Sken if ((arglist & CAM_ARG_BUS) 308446938Sken && (arglist & CAM_ARG_TARGET) 308546938Sken && (arglist & CAM_ARG_LUN)) 308646938Sken error = scanlun_or_reset_dev(bus, target, lun, rescan); 308746938Sken else 308846938Sken error = rescan_or_reset_bus(bus, rescan); 308939214Sgibbs 309039214Sgibbs return(error); 309139214Sgibbs} 309239214Sgibbs 309339214Sgibbsstatic int 3094260509Smavrescan_or_reset_bus(path_id_t bus, int rescan) 309539214Sgibbs{ 309689515Sken union ccb ccb, matchccb; 309789515Sken int fd, retval; 309889515Sken int bufsize; 309939214Sgibbs 310089515Sken retval = 0; 310139214Sgibbs 310239214Sgibbs if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { 3103166324Swilko warnx("error opening transport layer device %s", XPT_DEVICE); 310439214Sgibbs warn("%s", XPT_DEVICE); 310539214Sgibbs return(1); 310639214Sgibbs } 310739214Sgibbs 3108260509Smav if (bus != CAM_BUS_WILDCARD) { 310989515Sken ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS : XPT_RESET_BUS; 311089515Sken ccb.ccb_h.path_id = bus; 311189515Sken ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; 311289515Sken ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; 311389515Sken ccb.crcn.flags = CAM_FLAG_NONE; 311439214Sgibbs 311589515Sken /* run this at a low priority */ 311689515Sken ccb.ccb_h.pinfo.priority = 5; 311739214Sgibbs 311889515Sken if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 311989515Sken warn("CAMIOCOMMAND ioctl failed"); 312089515Sken close(fd); 312189515Sken return(1); 312289515Sken } 312389515Sken 312489515Sken if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 312589515Sken fprintf(stdout, "%s of bus %d was successful\n", 312689515Sken rescan ? "Re-scan" : "Reset", bus); 312789515Sken } else { 312889515Sken fprintf(stdout, "%s of bus %d returned error %#x\n", 312989515Sken rescan ? "Re-scan" : "Reset", bus, 313089515Sken ccb.ccb_h.status & CAM_STATUS_MASK); 313189515Sken retval = 1; 313289515Sken } 313389515Sken 313439214Sgibbs close(fd); 313589515Sken return(retval); 313689515Sken 313739214Sgibbs } 313839214Sgibbs 313939214Sgibbs 314089515Sken /* 314189515Sken * The right way to handle this is to modify the xpt so that it can 314289515Sken * handle a wildcarded bus in a rescan or reset CCB. At the moment 314389515Sken * that isn't implemented, so instead we enumerate the busses and 314489515Sken * send the rescan or reset to those busses in the case where the 314589515Sken * given bus is -1 (wildcard). We don't send a rescan or reset 314689515Sken * to the xpt bus; sending a rescan to the xpt bus is effectively a 314789515Sken * no-op, sending a rescan to the xpt bus would result in a status of 314889515Sken * CAM_REQ_INVALID. 314989515Sken */ 315089515Sken bzero(&(&matchccb.ccb_h)[1], 315189515Sken sizeof(struct ccb_dev_match) - sizeof(struct ccb_hdr)); 315289515Sken matchccb.ccb_h.func_code = XPT_DEV_MATCH; 3153215507Srstone matchccb.ccb_h.path_id = CAM_BUS_WILDCARD; 315489515Sken bufsize = sizeof(struct dev_match_result) * 20; 315589515Sken matchccb.cdm.match_buf_len = bufsize; 315689515Sken matchccb.cdm.matches=(struct dev_match_result *)malloc(bufsize); 315789515Sken if (matchccb.cdm.matches == NULL) { 315889515Sken warnx("can't malloc memory for matches"); 315989515Sken retval = 1; 316089515Sken goto bailout; 316139214Sgibbs } 316289515Sken matchccb.cdm.num_matches = 0; 316389515Sken 316489515Sken matchccb.cdm.num_patterns = 1; 316589515Sken matchccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern); 316689515Sken 316789515Sken matchccb.cdm.patterns = (struct dev_match_pattern *)malloc( 316889515Sken matchccb.cdm.pattern_buf_len); 316989515Sken if (matchccb.cdm.patterns == NULL) { 317089515Sken warnx("can't malloc memory for patterns"); 317189515Sken retval = 1; 317289515Sken goto bailout; 317389515Sken } 317489515Sken matchccb.cdm.patterns[0].type = DEV_MATCH_BUS; 317589515Sken matchccb.cdm.patterns[0].pattern.bus_pattern.flags = BUS_MATCH_ANY; 317689515Sken 317789515Sken do { 3178102192Sjohan unsigned int i; 317989515Sken 318089515Sken if (ioctl(fd, CAMIOCOMMAND, &matchccb) == -1) { 318189515Sken warn("CAMIOCOMMAND ioctl failed"); 318289515Sken retval = 1; 318389515Sken goto bailout; 318489515Sken } 318589515Sken 318689515Sken if ((matchccb.ccb_h.status != CAM_REQ_CMP) 318789515Sken || ((matchccb.cdm.status != CAM_DEV_MATCH_LAST) 318889515Sken && (matchccb.cdm.status != CAM_DEV_MATCH_MORE))) { 318989515Sken warnx("got CAM error %#x, CDM error %d\n", 319089515Sken matchccb.ccb_h.status, matchccb.cdm.status); 319189515Sken retval = 1; 319289515Sken goto bailout; 319389515Sken } 319489515Sken 319589515Sken for (i = 0; i < matchccb.cdm.num_matches; i++) { 319689515Sken struct bus_match_result *bus_result; 319789515Sken 319889515Sken /* This shouldn't happen. */ 319989515Sken if (matchccb.cdm.matches[i].type != DEV_MATCH_BUS) 320089515Sken continue; 320189515Sken 320289515Sken bus_result = &matchccb.cdm.matches[i].result.bus_result; 320389515Sken 320489515Sken /* 320589515Sken * We don't want to rescan or reset the xpt bus. 320689515Sken * See above. 320789515Sken */ 3208260509Smav if (bus_result->path_id == CAM_XPT_PATH_ID) 320989515Sken continue; 321089515Sken 321189515Sken ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS : 321289515Sken XPT_RESET_BUS; 321389515Sken ccb.ccb_h.path_id = bus_result->path_id; 321489515Sken ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; 321589515Sken ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; 321689515Sken ccb.crcn.flags = CAM_FLAG_NONE; 321789515Sken 321889515Sken /* run this at a low priority */ 321989515Sken ccb.ccb_h.pinfo.priority = 5; 322089515Sken 322189515Sken if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 322289515Sken warn("CAMIOCOMMAND ioctl failed"); 322389515Sken retval = 1; 322489515Sken goto bailout; 322589515Sken } 322689515Sken 322789515Sken if ((ccb.ccb_h.status & CAM_STATUS_MASK) ==CAM_REQ_CMP){ 322889515Sken fprintf(stdout, "%s of bus %d was successful\n", 322989515Sken rescan? "Re-scan" : "Reset", 323089515Sken bus_result->path_id); 323189515Sken } else { 323289515Sken /* 323389515Sken * Don't bail out just yet, maybe the other 323489515Sken * rescan or reset commands will complete 323589515Sken * successfully. 323689515Sken */ 323789515Sken fprintf(stderr, "%s of bus %d returned error " 323889515Sken "%#x\n", rescan? "Re-scan" : "Reset", 323989515Sken bus_result->path_id, 324089515Sken ccb.ccb_h.status & CAM_STATUS_MASK); 324189515Sken retval = 1; 324289515Sken } 324389515Sken } 324489515Sken } while ((matchccb.ccb_h.status == CAM_REQ_CMP) 324589515Sken && (matchccb.cdm.status == CAM_DEV_MATCH_MORE)); 324689515Sken 324789515Skenbailout: 324889515Sken 324989515Sken if (fd != -1) 325089515Sken close(fd); 325189515Sken 325289515Sken if (matchccb.cdm.patterns != NULL) 325389515Sken free(matchccb.cdm.patterns); 325489515Sken if (matchccb.cdm.matches != NULL) 325589515Sken free(matchccb.cdm.matches); 325689515Sken 325789515Sken return(retval); 325839214Sgibbs} 325939214Sgibbs 326039214Sgibbsstatic int 3261260509Smavscanlun_or_reset_dev(path_id_t bus, target_id_t target, lun_id_t lun, int scan) 326239214Sgibbs{ 326339214Sgibbs union ccb ccb; 326452703Sken struct cam_device *device; 326539214Sgibbs int fd; 326639214Sgibbs 326761233Sken device = NULL; 326861233Sken 3269260509Smav if (bus == CAM_BUS_WILDCARD) { 327039214Sgibbs warnx("invalid bus number %d", bus); 327139214Sgibbs return(1); 327239214Sgibbs } 327339214Sgibbs 3274260509Smav if (target == CAM_TARGET_WILDCARD) { 327539214Sgibbs warnx("invalid target number %d", target); 327639214Sgibbs return(1); 327739214Sgibbs } 327839214Sgibbs 3279260509Smav if (lun == CAM_LUN_WILDCARD) { 3280260509Smav warnx("invalid lun number %jx", (uintmax_t)lun); 328139214Sgibbs return(1); 328239214Sgibbs } 328339214Sgibbs 328452703Sken fd = -1; 328552703Sken 328652703Sken bzero(&ccb, sizeof(union ccb)); 328752703Sken 328852703Sken if (scan) { 328952703Sken if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { 3290166324Swilko warnx("error opening transport layer device %s\n", 329152703Sken XPT_DEVICE); 329252703Sken warn("%s", XPT_DEVICE); 329352703Sken return(1); 329452703Sken } 329552703Sken } else { 329652703Sken device = cam_open_btl(bus, target, lun, O_RDWR, NULL); 329752703Sken if (device == NULL) { 329852703Sken warnx("%s", cam_errbuf); 329952703Sken return(1); 330052703Sken } 330139214Sgibbs } 330239214Sgibbs 330341962Smjacob ccb.ccb_h.func_code = (scan)? XPT_SCAN_LUN : XPT_RESET_DEV; 330439214Sgibbs ccb.ccb_h.path_id = bus; 330539214Sgibbs ccb.ccb_h.target_id = target; 330639214Sgibbs ccb.ccb_h.target_lun = lun; 330752703Sken ccb.ccb_h.timeout = 5000; 330839214Sgibbs ccb.crcn.flags = CAM_FLAG_NONE; 330939214Sgibbs 331039214Sgibbs /* run this at a low priority */ 331139214Sgibbs ccb.ccb_h.pinfo.priority = 5; 331239214Sgibbs 331352703Sken if (scan) { 331452703Sken if (ioctl(fd, CAMIOCOMMAND, &ccb) < 0) { 331552703Sken warn("CAMIOCOMMAND ioctl failed"); 331652703Sken close(fd); 331752703Sken return(1); 331852703Sken } 331952703Sken } else { 332052703Sken if (cam_send_ccb(device, &ccb) < 0) { 332152703Sken warn("error sending XPT_RESET_DEV CCB"); 332252703Sken cam_close_device(device); 332352703Sken return(1); 332452703Sken } 332539214Sgibbs } 332639214Sgibbs 332752703Sken if (scan) 332852703Sken close(fd); 332952703Sken else 333052703Sken cam_close_device(device); 333139214Sgibbs 333252703Sken /* 333352703Sken * An error code of CAM_BDR_SENT is normal for a BDR request. 333452703Sken */ 333552703Sken if (((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 333652703Sken || ((!scan) 333752703Sken && ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_BDR_SENT))) { 3338260509Smav fprintf(stdout, "%s of %d:%d:%jx was successful\n", 3339260509Smav scan? "Re-scan" : "Reset", bus, target, (uintmax_t)lun); 334039214Sgibbs return(0); 334139214Sgibbs } else { 3342260509Smav fprintf(stdout, "%s of %d:%d:%jx returned error %#x\n", 3343260509Smav scan? "Re-scan" : "Reset", bus, target, (uintmax_t)lun, 334441962Smjacob ccb.ccb_h.status & CAM_STATUS_MASK); 334539214Sgibbs return(1); 334639214Sgibbs } 334739214Sgibbs} 334839214Sgibbs 334989471Sjoerg#ifndef MINIMALISTIC 335039214Sgibbsstatic int 335139214Sgibbsreaddefects(struct cam_device *device, int argc, char **argv, 335239214Sgibbs char *combinedopt, int retry_count, int timeout) 335339214Sgibbs{ 335439214Sgibbs union ccb *ccb = NULL; 335539214Sgibbs struct scsi_read_defect_data_10 *rdd_cdb; 335639214Sgibbs u_int8_t *defect_list = NULL; 3357237452Sken u_int32_t max_dlist_length = SRDD10_MAX_LENGTH, dlist_length = 0; 335839214Sgibbs u_int32_t returned_length = 0; 335939214Sgibbs u_int32_t num_returned = 0; 336039214Sgibbs u_int8_t returned_format; 3361102192Sjohan unsigned int i; 336239214Sgibbs int c, error = 0; 3363237452Sken int lists_specified; 3364237452Sken int get_length = 1; 336539214Sgibbs 336639214Sgibbs while ((c = getopt(argc, argv, combinedopt)) != -1) { 336739214Sgibbs switch(c){ 336839214Sgibbs case 'f': 336939214Sgibbs { 337039214Sgibbs char *tstr; 337139214Sgibbs tstr = optarg; 337239214Sgibbs while (isspace(*tstr) && (*tstr != '\0')) 337339214Sgibbs tstr++; 337439214Sgibbs if (strcmp(tstr, "block") == 0) 337539214Sgibbs arglist |= CAM_ARG_FORMAT_BLOCK; 337639214Sgibbs else if (strcmp(tstr, "bfi") == 0) 337739214Sgibbs arglist |= CAM_ARG_FORMAT_BFI; 337839214Sgibbs else if (strcmp(tstr, "phys") == 0) 337939214Sgibbs arglist |= CAM_ARG_FORMAT_PHYS; 338039214Sgibbs else { 338139214Sgibbs error = 1; 338239214Sgibbs warnx("invalid defect format %s", tstr); 338339214Sgibbs goto defect_bailout; 338439214Sgibbs } 338539214Sgibbs break; 338639214Sgibbs } 338739214Sgibbs case 'G': 338839214Sgibbs arglist |= CAM_ARG_GLIST; 338939214Sgibbs break; 339039214Sgibbs case 'P': 339139214Sgibbs arglist |= CAM_ARG_PLIST; 339239214Sgibbs break; 339339214Sgibbs default: 339439214Sgibbs break; 339539214Sgibbs } 339639214Sgibbs } 339739214Sgibbs 339839214Sgibbs ccb = cam_getccb(device); 339939214Sgibbs 340039214Sgibbs /* 3401237452Sken * Eventually we should probably support the 12 byte READ DEFECT 3402237452Sken * DATA command. It supports a longer parameter list, which may be 3403237452Sken * necessary on newer drives with lots of defects. According to 3404237452Sken * the SBC-3 spec, drives are supposed to return an illegal request 3405237452Sken * if they have more defect data than will fit in 64K. 340639214Sgibbs */ 3407237452Sken defect_list = malloc(max_dlist_length); 340869471Sjedgar if (defect_list == NULL) { 340969471Sjedgar warnx("can't malloc memory for defect list"); 341069471Sjedgar error = 1; 341169471Sjedgar goto defect_bailout; 341269471Sjedgar } 341339214Sgibbs 3414237452Sken /* 3415237452Sken * We start off asking for just the header to determine how much 3416237452Sken * defect data is available. Some Hitachi drives return an error 3417237452Sken * if you ask for more data than the drive has. Once we know the 3418237452Sken * length, we retry the command with the returned length. 3419237452Sken */ 3420237452Sken dlist_length = sizeof(struct scsi_read_defect_data_hdr_10); 3421237452Sken 342239214Sgibbs rdd_cdb =(struct scsi_read_defect_data_10 *)&ccb->csio.cdb_io.cdb_bytes; 342339214Sgibbs 3424237452Skenretry: 3425237452Sken 3426237452Sken lists_specified = 0; 3427237452Sken 342839214Sgibbs /* 342939214Sgibbs * cam_getccb() zeros the CCB header only. So we need to zero the 343039214Sgibbs * payload portion of the ccb. 343139214Sgibbs */ 343246581Sken bzero(&(&ccb->ccb_h)[1], 343346581Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 343439214Sgibbs 343539214Sgibbs cam_fill_csio(&ccb->csio, 343639214Sgibbs /*retries*/ retry_count, 343739214Sgibbs /*cbfcnp*/ NULL, 343851723Sken /*flags*/ CAM_DIR_IN | ((arglist & CAM_ARG_ERR_RECOVER) ? 343951723Sken CAM_PASS_ERR_RECOVER : 0), 344039214Sgibbs /*tag_action*/ MSG_SIMPLE_Q_TAG, 344139214Sgibbs /*data_ptr*/ defect_list, 344239214Sgibbs /*dxfer_len*/ dlist_length, 344339214Sgibbs /*sense_len*/ SSD_FULL_SIZE, 344439214Sgibbs /*cdb_len*/ sizeof(struct scsi_read_defect_data_10), 344539214Sgibbs /*timeout*/ timeout ? timeout : 5000); 344639214Sgibbs 344739214Sgibbs rdd_cdb->opcode = READ_DEFECT_DATA_10; 344839214Sgibbs if (arglist & CAM_ARG_FORMAT_BLOCK) 344939214Sgibbs rdd_cdb->format = SRDD10_BLOCK_FORMAT; 345039214Sgibbs else if (arglist & CAM_ARG_FORMAT_BFI) 345139214Sgibbs rdd_cdb->format = SRDD10_BYTES_FROM_INDEX_FORMAT; 345239214Sgibbs else if (arglist & CAM_ARG_FORMAT_PHYS) 345339214Sgibbs rdd_cdb->format = SRDD10_PHYSICAL_SECTOR_FORMAT; 345439214Sgibbs else { 345539214Sgibbs error = 1; 345639214Sgibbs warnx("no defect list format specified"); 345739214Sgibbs goto defect_bailout; 345839214Sgibbs } 345939214Sgibbs if (arglist & CAM_ARG_PLIST) { 346039214Sgibbs rdd_cdb->format |= SRDD10_PLIST; 346139214Sgibbs lists_specified++; 346239214Sgibbs } 346339214Sgibbs 346439214Sgibbs if (arglist & CAM_ARG_GLIST) { 346539214Sgibbs rdd_cdb->format |= SRDD10_GLIST; 346639214Sgibbs lists_specified++; 346739214Sgibbs } 346839214Sgibbs 346939214Sgibbs scsi_ulto2b(dlist_length, rdd_cdb->alloc_length); 347039214Sgibbs 347139214Sgibbs /* Disable freezing the device queue */ 347239214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 347339214Sgibbs 347439214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 347539214Sgibbs perror("error reading defect list"); 347639214Sgibbs 347739214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 347874840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 347974840Sken CAM_EPF_ALL, stderr); 348039214Sgibbs } 348139214Sgibbs 348239214Sgibbs error = 1; 348339214Sgibbs goto defect_bailout; 348439214Sgibbs } 348539214Sgibbs 348639214Sgibbs returned_length = scsi_2btoul(((struct 348739214Sgibbs scsi_read_defect_data_hdr_10 *)defect_list)->length); 348839214Sgibbs 3489237452Sken if (get_length != 0) { 3490237452Sken get_length = 0; 3491237452Sken 3492237452Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 3493237452Sken CAM_SCSI_STATUS_ERROR) { 3494237452Sken struct scsi_sense_data *sense; 3495237452Sken int error_code, sense_key, asc, ascq; 3496237452Sken 3497237452Sken sense = &ccb->csio.sense_data; 3498237452Sken scsi_extract_sense_len(sense, ccb->csio.sense_len - 3499237452Sken ccb->csio.sense_resid, &error_code, &sense_key, 3500237452Sken &asc, &ascq, /*show_errors*/ 1); 3501237452Sken 3502237452Sken /* 3503237452Sken * If the drive is reporting that it just doesn't 3504237452Sken * support the defect list format, go ahead and use 3505237452Sken * the length it reported. Otherwise, the length 3506237452Sken * may not be valid, so use the maximum. 3507237452Sken */ 3508237452Sken if ((sense_key == SSD_KEY_RECOVERED_ERROR) 3509237452Sken && (asc == 0x1c) && (ascq == 0x00) 3510237452Sken && (returned_length > 0)) { 3511237452Sken dlist_length = returned_length + 3512237452Sken sizeof(struct scsi_read_defect_data_hdr_10); 3513237452Sken dlist_length = min(dlist_length, 3514237452Sken SRDD10_MAX_LENGTH); 3515237452Sken } else 3516237452Sken dlist_length = max_dlist_length; 3517237452Sken } else if ((ccb->ccb_h.status & CAM_STATUS_MASK) != 3518237452Sken CAM_REQ_CMP){ 3519237452Sken error = 1; 3520237452Sken warnx("Error reading defect header"); 3521237452Sken if (arglist & CAM_ARG_VERBOSE) 3522237452Sken cam_error_print(device, ccb, CAM_ESF_ALL, 3523237452Sken CAM_EPF_ALL, stderr); 3524237452Sken goto defect_bailout; 3525237452Sken } else { 3526237452Sken dlist_length = returned_length + 3527237452Sken sizeof(struct scsi_read_defect_data_hdr_10); 3528237452Sken dlist_length = min(dlist_length, SRDD10_MAX_LENGTH); 3529237452Sken } 3530237452Sken 3531237452Sken goto retry; 3532237452Sken } 3533237452Sken 353439214Sgibbs returned_format = ((struct scsi_read_defect_data_hdr_10 *) 353539214Sgibbs defect_list)->format; 353639214Sgibbs 353774840Sken if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) 353874840Sken && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) 353974840Sken && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) { 354039214Sgibbs struct scsi_sense_data *sense; 354139214Sgibbs int error_code, sense_key, asc, ascq; 354239214Sgibbs 354339214Sgibbs sense = &ccb->csio.sense_data; 3544225950Sken scsi_extract_sense_len(sense, ccb->csio.sense_len - 3545225950Sken ccb->csio.sense_resid, &error_code, &sense_key, &asc, 3546225950Sken &ascq, /*show_errors*/ 1); 354739214Sgibbs 354839214Sgibbs /* 354939214Sgibbs * According to the SCSI spec, if the disk doesn't support 355039214Sgibbs * the requested format, it will generally return a sense 355139214Sgibbs * key of RECOVERED ERROR, and an additional sense code 355239214Sgibbs * of "DEFECT LIST NOT FOUND". So, we check for that, and 355339214Sgibbs * also check to make sure that the returned length is 355439214Sgibbs * greater than 0, and then print out whatever format the 355539214Sgibbs * disk gave us. 355639214Sgibbs */ 355739214Sgibbs if ((sense_key == SSD_KEY_RECOVERED_ERROR) 355839214Sgibbs && (asc == 0x1c) && (ascq == 0x00) 355939214Sgibbs && (returned_length > 0)) { 356039214Sgibbs warnx("requested defect format not available"); 356139214Sgibbs switch(returned_format & SRDDH10_DLIST_FORMAT_MASK) { 356239214Sgibbs case SRDD10_BLOCK_FORMAT: 356339214Sgibbs warnx("Device returned block format"); 356439214Sgibbs break; 356539214Sgibbs case SRDD10_BYTES_FROM_INDEX_FORMAT: 356639214Sgibbs warnx("Device returned bytes from index" 356739214Sgibbs " format"); 356839214Sgibbs break; 356939214Sgibbs case SRDD10_PHYSICAL_SECTOR_FORMAT: 357039214Sgibbs warnx("Device returned physical sector format"); 357139214Sgibbs break; 357239214Sgibbs default: 357339214Sgibbs error = 1; 357439214Sgibbs warnx("Device returned unknown defect" 357539214Sgibbs " data format %#x", returned_format); 357639214Sgibbs goto defect_bailout; 357739214Sgibbs break; /* NOTREACHED */ 357839214Sgibbs } 357939214Sgibbs } else { 358039214Sgibbs error = 1; 358139214Sgibbs warnx("Error returned from read defect data command"); 358274840Sken if (arglist & CAM_ARG_VERBOSE) 358374840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 358474840Sken CAM_EPF_ALL, stderr); 358539214Sgibbs goto defect_bailout; 358639214Sgibbs } 358787378Sken } else if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 358874840Sken error = 1; 358974840Sken warnx("Error returned from read defect data command"); 359074840Sken if (arglist & CAM_ARG_VERBOSE) 359174840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 359274840Sken CAM_EPF_ALL, stderr); 359374840Sken goto defect_bailout; 359439214Sgibbs } 359539214Sgibbs 359639214Sgibbs /* 359739214Sgibbs * XXX KDM I should probably clean up the printout format for the 3598214321Smav * disk defects. 359939214Sgibbs */ 360039214Sgibbs switch (returned_format & SRDDH10_DLIST_FORMAT_MASK){ 360139214Sgibbs case SRDDH10_PHYSICAL_SECTOR_FORMAT: 360239214Sgibbs { 360339214Sgibbs struct scsi_defect_desc_phys_sector *dlist; 360439214Sgibbs 360539214Sgibbs dlist = (struct scsi_defect_desc_phys_sector *) 360639214Sgibbs (defect_list + 360739214Sgibbs sizeof(struct scsi_read_defect_data_hdr_10)); 360839214Sgibbs 360939214Sgibbs num_returned = returned_length / 361039214Sgibbs sizeof(struct scsi_defect_desc_phys_sector); 361139214Sgibbs 361239214Sgibbs fprintf(stderr, "Got %d defect", num_returned); 361339214Sgibbs 361439214Sgibbs if ((lists_specified == 0) || (num_returned == 0)) { 361539214Sgibbs fprintf(stderr, "s.\n"); 361639214Sgibbs break; 361739214Sgibbs } else if (num_returned == 1) 361839214Sgibbs fprintf(stderr, ":\n"); 361939214Sgibbs else 362039214Sgibbs fprintf(stderr, "s:\n"); 362139214Sgibbs 362239214Sgibbs for (i = 0; i < num_returned; i++) { 362339214Sgibbs fprintf(stdout, "%d:%d:%d\n", 362439214Sgibbs scsi_3btoul(dlist[i].cylinder), 362539214Sgibbs dlist[i].head, 362639214Sgibbs scsi_4btoul(dlist[i].sector)); 362739214Sgibbs } 362839214Sgibbs break; 362939214Sgibbs } 363039214Sgibbs case SRDDH10_BYTES_FROM_INDEX_FORMAT: 363139214Sgibbs { 363239214Sgibbs struct scsi_defect_desc_bytes_from_index *dlist; 363339214Sgibbs 363439214Sgibbs dlist = (struct scsi_defect_desc_bytes_from_index *) 363539214Sgibbs (defect_list + 363639214Sgibbs sizeof(struct scsi_read_defect_data_hdr_10)); 363739214Sgibbs 363839214Sgibbs num_returned = returned_length / 363939214Sgibbs sizeof(struct scsi_defect_desc_bytes_from_index); 364039214Sgibbs 364139214Sgibbs fprintf(stderr, "Got %d defect", num_returned); 364239214Sgibbs 364339214Sgibbs if ((lists_specified == 0) || (num_returned == 0)) { 364439214Sgibbs fprintf(stderr, "s.\n"); 364539214Sgibbs break; 364639214Sgibbs } else if (num_returned == 1) 364739214Sgibbs fprintf(stderr, ":\n"); 364839214Sgibbs else 364939214Sgibbs fprintf(stderr, "s:\n"); 365039214Sgibbs 365139214Sgibbs for (i = 0; i < num_returned; i++) { 365239214Sgibbs fprintf(stdout, "%d:%d:%d\n", 365339214Sgibbs scsi_3btoul(dlist[i].cylinder), 365439214Sgibbs dlist[i].head, 365539214Sgibbs scsi_4btoul(dlist[i].bytes_from_index)); 365639214Sgibbs } 365739214Sgibbs break; 365839214Sgibbs } 365939214Sgibbs case SRDDH10_BLOCK_FORMAT: 366039214Sgibbs { 366139214Sgibbs struct scsi_defect_desc_block *dlist; 366239214Sgibbs 366339214Sgibbs dlist = (struct scsi_defect_desc_block *)(defect_list + 366439214Sgibbs sizeof(struct scsi_read_defect_data_hdr_10)); 366539214Sgibbs 366639214Sgibbs num_returned = returned_length / 366739214Sgibbs sizeof(struct scsi_defect_desc_block); 366839214Sgibbs 366939214Sgibbs fprintf(stderr, "Got %d defect", num_returned); 367039214Sgibbs 367139214Sgibbs if ((lists_specified == 0) || (num_returned == 0)) { 367239214Sgibbs fprintf(stderr, "s.\n"); 367339214Sgibbs break; 367439214Sgibbs } else if (num_returned == 1) 367539214Sgibbs fprintf(stderr, ":\n"); 367639214Sgibbs else 367739214Sgibbs fprintf(stderr, "s:\n"); 367839214Sgibbs 367939214Sgibbs for (i = 0; i < num_returned; i++) 368039214Sgibbs fprintf(stdout, "%u\n", 368139214Sgibbs scsi_4btoul(dlist[i].address)); 368239214Sgibbs break; 368339214Sgibbs } 368439214Sgibbs default: 368539214Sgibbs fprintf(stderr, "Unknown defect format %d\n", 368639214Sgibbs returned_format & SRDDH10_DLIST_FORMAT_MASK); 368739214Sgibbs error = 1; 368839214Sgibbs break; 368939214Sgibbs } 369039214Sgibbsdefect_bailout: 369139214Sgibbs 369239214Sgibbs if (defect_list != NULL) 369339214Sgibbs free(defect_list); 369439214Sgibbs 369539214Sgibbs if (ccb != NULL) 369639214Sgibbs cam_freeccb(ccb); 369739214Sgibbs 369839214Sgibbs return(error); 369939214Sgibbs} 370089471Sjoerg#endif /* MINIMALISTIC */ 370139214Sgibbs 370239214Sgibbs#if 0 370339214Sgibbsvoid 370439214Sgibbsreassignblocks(struct cam_device *device, u_int32_t *blocks, int num_blocks) 370539214Sgibbs{ 370639214Sgibbs union ccb *ccb; 3707214321Smav 370839214Sgibbs ccb = cam_getccb(device); 370939214Sgibbs 371039214Sgibbs cam_freeccb(ccb); 371139214Sgibbs} 371239214Sgibbs#endif 371339214Sgibbs 371489471Sjoerg#ifndef MINIMALISTIC 371539214Sgibbsvoid 371639214Sgibbsmode_sense(struct cam_device *device, int mode_page, int page_control, 371739214Sgibbs int dbd, int retry_count, int timeout, u_int8_t *data, int datalen) 371839214Sgibbs{ 371939214Sgibbs union ccb *ccb; 372039214Sgibbs int retval; 372139214Sgibbs 372239214Sgibbs ccb = cam_getccb(device); 372339214Sgibbs 372439214Sgibbs if (ccb == NULL) 372539214Sgibbs errx(1, "mode_sense: couldn't allocate CCB"); 372639214Sgibbs 372746581Sken bzero(&(&ccb->ccb_h)[1], 372846581Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 372939214Sgibbs 373039214Sgibbs scsi_mode_sense(&ccb->csio, 373139214Sgibbs /* retries */ retry_count, 373239214Sgibbs /* cbfcnp */ NULL, 373339214Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 373439214Sgibbs /* dbd */ dbd, 373539214Sgibbs /* page_code */ page_control << 6, 373639214Sgibbs /* page */ mode_page, 373739214Sgibbs /* param_buf */ data, 373839214Sgibbs /* param_len */ datalen, 373939214Sgibbs /* sense_len */ SSD_FULL_SIZE, 374039214Sgibbs /* timeout */ timeout ? timeout : 5000); 374139214Sgibbs 374239214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 374339214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 374439214Sgibbs 374539214Sgibbs /* Disable freezing the device queue */ 374639214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 374739214Sgibbs 374839214Sgibbs if (((retval = cam_send_ccb(device, ccb)) < 0) 374939214Sgibbs || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 375039214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 375174840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 375274840Sken CAM_EPF_ALL, stderr); 375339214Sgibbs } 375439214Sgibbs cam_freeccb(ccb); 375539214Sgibbs cam_close_device(device); 375639214Sgibbs if (retval < 0) 375739214Sgibbs err(1, "error sending mode sense command"); 375839214Sgibbs else 375939214Sgibbs errx(1, "error sending mode sense command"); 376039214Sgibbs } 376139214Sgibbs 376239214Sgibbs cam_freeccb(ccb); 376339214Sgibbs} 376439214Sgibbs 376539214Sgibbsvoid 376639214Sgibbsmode_select(struct cam_device *device, int save_pages, int retry_count, 376739214Sgibbs int timeout, u_int8_t *data, int datalen) 376839214Sgibbs{ 376939214Sgibbs union ccb *ccb; 377039214Sgibbs int retval; 377139214Sgibbs 377239214Sgibbs ccb = cam_getccb(device); 377339214Sgibbs 377439214Sgibbs if (ccb == NULL) 377539214Sgibbs errx(1, "mode_select: couldn't allocate CCB"); 377639214Sgibbs 377746581Sken bzero(&(&ccb->ccb_h)[1], 377846581Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 377939214Sgibbs 378039214Sgibbs scsi_mode_select(&ccb->csio, 378139214Sgibbs /* retries */ retry_count, 378239214Sgibbs /* cbfcnp */ NULL, 378339214Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 378439214Sgibbs /* scsi_page_fmt */ 1, 378539214Sgibbs /* save_pages */ save_pages, 378639214Sgibbs /* param_buf */ data, 378739214Sgibbs /* param_len */ datalen, 378839214Sgibbs /* sense_len */ SSD_FULL_SIZE, 378939214Sgibbs /* timeout */ timeout ? timeout : 5000); 379039214Sgibbs 379139214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 379239214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 379339214Sgibbs 379439214Sgibbs /* Disable freezing the device queue */ 379539214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 379639214Sgibbs 379739214Sgibbs if (((retval = cam_send_ccb(device, ccb)) < 0) 379839214Sgibbs || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 379939214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 380074840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 380174840Sken CAM_EPF_ALL, stderr); 380239214Sgibbs } 380339214Sgibbs cam_freeccb(ccb); 380439214Sgibbs cam_close_device(device); 380539214Sgibbs 380639214Sgibbs if (retval < 0) 380739214Sgibbs err(1, "error sending mode select command"); 380839214Sgibbs else 380939214Sgibbs errx(1, "error sending mode select command"); 3810214321Smav 381139214Sgibbs } 381239214Sgibbs 381339214Sgibbs cam_freeccb(ccb); 381439214Sgibbs} 381539214Sgibbs 381639214Sgibbsvoid 381739214Sgibbsmodepage(struct cam_device *device, int argc, char **argv, char *combinedopt, 381839214Sgibbs int retry_count, int timeout) 381939214Sgibbs{ 382039214Sgibbs int c, mode_page = -1, page_control = 0; 382164382Skbyanc int binary = 0, list = 0; 382239214Sgibbs 382339214Sgibbs while ((c = getopt(argc, argv, combinedopt)) != -1) { 382439214Sgibbs switch(c) { 382564382Skbyanc case 'b': 382664382Skbyanc binary = 1; 382764382Skbyanc break; 382839214Sgibbs case 'd': 382939214Sgibbs arglist |= CAM_ARG_DBD; 383039214Sgibbs break; 383139214Sgibbs case 'e': 383239214Sgibbs arglist |= CAM_ARG_MODE_EDIT; 383339214Sgibbs break; 383464382Skbyanc case 'l': 383564382Skbyanc list = 1; 383664382Skbyanc break; 383739214Sgibbs case 'm': 383839214Sgibbs mode_page = strtol(optarg, NULL, 0); 383939214Sgibbs if (mode_page < 0) 384039214Sgibbs errx(1, "invalid mode page %d", mode_page); 384139214Sgibbs break; 384239214Sgibbs case 'P': 384339214Sgibbs page_control = strtol(optarg, NULL, 0); 384439214Sgibbs if ((page_control < 0) || (page_control > 3)) 384539214Sgibbs errx(1, "invalid page control field %d", 384639214Sgibbs page_control); 384739214Sgibbs arglist |= CAM_ARG_PAGE_CNTL; 384839214Sgibbs break; 384939214Sgibbs default: 385039214Sgibbs break; 385139214Sgibbs } 385239214Sgibbs } 385339214Sgibbs 385464382Skbyanc if (mode_page == -1 && list == 0) 385539214Sgibbs errx(1, "you must specify a mode page!"); 385639214Sgibbs 385764382Skbyanc if (list) { 385864382Skbyanc mode_list(device, page_control, arglist & CAM_ARG_DBD, 385964382Skbyanc retry_count, timeout); 386064382Skbyanc } else { 386164382Skbyanc mode_edit(device, mode_page, page_control, 386264382Skbyanc arglist & CAM_ARG_DBD, arglist & CAM_ARG_MODE_EDIT, binary, 386364382Skbyanc retry_count, timeout); 386464382Skbyanc } 386539214Sgibbs} 386639214Sgibbs 386739214Sgibbsstatic int 386839214Sgibbsscsicmd(struct cam_device *device, int argc, char **argv, char *combinedopt, 386939214Sgibbs int retry_count, int timeout) 387039214Sgibbs{ 387139214Sgibbs union ccb *ccb; 387239214Sgibbs u_int32_t flags = CAM_DIR_NONE; 387339214Sgibbs u_int8_t *data_ptr = NULL; 387439214Sgibbs u_int8_t cdb[20]; 3875196831Smav u_int8_t atacmd[12]; 387639214Sgibbs struct get_hook hook; 387739214Sgibbs int c, data_bytes = 0; 387839214Sgibbs int cdb_len = 0; 3879196831Smav int atacmd_len = 0; 3880207498Smav int dmacmd = 0; 3881207498Smav int fpdmacmd = 0; 3882196831Smav int need_res = 0; 3883196831Smav char *datastr = NULL, *tstr, *resstr = NULL; 388439214Sgibbs int error = 0; 3885196831Smav int fd_data = 0, fd_res = 0; 388639214Sgibbs int retval; 388739214Sgibbs 388839214Sgibbs ccb = cam_getccb(device); 388939214Sgibbs 389039214Sgibbs if (ccb == NULL) { 389139214Sgibbs warnx("scsicmd: error allocating ccb"); 389239214Sgibbs return(1); 389339214Sgibbs } 389439214Sgibbs 389546581Sken bzero(&(&ccb->ccb_h)[1], 3896196831Smav sizeof(union ccb) - sizeof(struct ccb_hdr)); 389739214Sgibbs 389839214Sgibbs while ((c = getopt(argc, argv, combinedopt)) != -1) { 389939214Sgibbs switch(c) { 3900196831Smav case 'a': 3901196831Smav tstr = optarg; 3902196831Smav while (isspace(*tstr) && (*tstr != '\0')) 3903196831Smav tstr++; 3904196831Smav hook.argc = argc - optind; 3905196831Smav hook.argv = argv + optind; 3906196831Smav hook.got = 0; 3907196831Smav atacmd_len = buff_encode_visit(atacmd, sizeof(atacmd), tstr, 3908196831Smav iget, &hook); 3909196831Smav /* 3910196831Smav * Increment optind by the number of arguments the 3911196831Smav * encoding routine processed. After each call to 3912196831Smav * getopt(3), optind points to the argument that 3913196831Smav * getopt should process _next_. In this case, 3914196831Smav * that means it points to the first command string 3915196831Smav * argument, if there is one. Once we increment 3916196831Smav * this, it should point to either the next command 3917196831Smav * line argument, or it should be past the end of 3918196831Smav * the list. 3919196831Smav */ 3920196831Smav optind += hook.got; 3921196831Smav break; 392239214Sgibbs case 'c': 392339214Sgibbs tstr = optarg; 392439214Sgibbs while (isspace(*tstr) && (*tstr != '\0')) 392539214Sgibbs tstr++; 392639214Sgibbs hook.argc = argc - optind; 392739214Sgibbs hook.argv = argv + optind; 392839214Sgibbs hook.got = 0; 392947867Sken cdb_len = buff_encode_visit(cdb, sizeof(cdb), tstr, 393047867Sken iget, &hook); 393139214Sgibbs /* 393239214Sgibbs * Increment optind by the number of arguments the 393339214Sgibbs * encoding routine processed. After each call to 393439214Sgibbs * getopt(3), optind points to the argument that 393539214Sgibbs * getopt should process _next_. In this case, 393639214Sgibbs * that means it points to the first command string 393739214Sgibbs * argument, if there is one. Once we increment 393839214Sgibbs * this, it should point to either the next command 393939214Sgibbs * line argument, or it should be past the end of 394039214Sgibbs * the list. 394139214Sgibbs */ 394239214Sgibbs optind += hook.got; 394339214Sgibbs break; 3944207498Smav case 'd': 3945207498Smav dmacmd = 1; 3946207498Smav break; 3947207498Smav case 'f': 3948207498Smav fpdmacmd = 1; 3949207498Smav break; 395039214Sgibbs case 'i': 395139214Sgibbs if (arglist & CAM_ARG_CMD_OUT) { 395239214Sgibbs warnx("command must either be " 395339214Sgibbs "read or write, not both"); 395439214Sgibbs error = 1; 395539214Sgibbs goto scsicmd_bailout; 395639214Sgibbs } 395739214Sgibbs arglist |= CAM_ARG_CMD_IN; 395839214Sgibbs flags = CAM_DIR_IN; 395939214Sgibbs data_bytes = strtol(optarg, NULL, 0); 396039214Sgibbs if (data_bytes <= 0) { 396139214Sgibbs warnx("invalid number of input bytes %d", 396239214Sgibbs data_bytes); 396339214Sgibbs error = 1; 396439214Sgibbs goto scsicmd_bailout; 396539214Sgibbs } 396639214Sgibbs hook.argc = argc - optind; 396739214Sgibbs hook.argv = argv + optind; 396839214Sgibbs hook.got = 0; 396939214Sgibbs optind++; 397039214Sgibbs datastr = cget(&hook, NULL); 397139214Sgibbs /* 397239214Sgibbs * If the user supplied "-" instead of a format, he 397339214Sgibbs * wants the data to be written to stdout. 397439214Sgibbs */ 397539214Sgibbs if ((datastr != NULL) 397639214Sgibbs && (datastr[0] == '-')) 397739214Sgibbs fd_data = 1; 397839214Sgibbs 397939214Sgibbs data_ptr = (u_int8_t *)malloc(data_bytes); 398069471Sjedgar if (data_ptr == NULL) { 398169471Sjedgar warnx("can't malloc memory for data_ptr"); 398269471Sjedgar error = 1; 398369471Sjedgar goto scsicmd_bailout; 398469471Sjedgar } 398539214Sgibbs break; 398639214Sgibbs case 'o': 398739214Sgibbs if (arglist & CAM_ARG_CMD_IN) { 398839214Sgibbs warnx("command must either be " 398939214Sgibbs "read or write, not both"); 3990214321Smav error = 1; 399139214Sgibbs goto scsicmd_bailout; 399239214Sgibbs } 399339214Sgibbs arglist |= CAM_ARG_CMD_OUT; 399439214Sgibbs flags = CAM_DIR_OUT; 399539214Sgibbs data_bytes = strtol(optarg, NULL, 0); 399639214Sgibbs if (data_bytes <= 0) { 399739214Sgibbs warnx("invalid number of output bytes %d", 399839214Sgibbs data_bytes); 399939214Sgibbs error = 1; 400039214Sgibbs goto scsicmd_bailout; 400139214Sgibbs } 400239214Sgibbs hook.argc = argc - optind; 400339214Sgibbs hook.argv = argv + optind; 400439214Sgibbs hook.got = 0; 400539214Sgibbs datastr = cget(&hook, NULL); 400639214Sgibbs data_ptr = (u_int8_t *)malloc(data_bytes); 400769471Sjedgar if (data_ptr == NULL) { 400869471Sjedgar warnx("can't malloc memory for data_ptr"); 400969471Sjedgar error = 1; 401069471Sjedgar goto scsicmd_bailout; 401169471Sjedgar } 4012202694Smav bzero(data_ptr, data_bytes); 401339214Sgibbs /* 401439214Sgibbs * If the user supplied "-" instead of a format, he 401539214Sgibbs * wants the data to be read from stdin. 401639214Sgibbs */ 401739214Sgibbs if ((datastr != NULL) 401839214Sgibbs && (datastr[0] == '-')) 401939214Sgibbs fd_data = 1; 402039214Sgibbs else 402139214Sgibbs buff_encode_visit(data_ptr, data_bytes, datastr, 402239214Sgibbs iget, &hook); 402339214Sgibbs optind += hook.got; 402439214Sgibbs break; 4025196831Smav case 'r': 4026196831Smav need_res = 1; 4027196831Smav hook.argc = argc - optind; 4028196831Smav hook.argv = argv + optind; 4029196831Smav hook.got = 0; 4030196831Smav resstr = cget(&hook, NULL); 4031196831Smav if ((resstr != NULL) && (resstr[0] == '-')) 4032196831Smav fd_res = 1; 4033196831Smav optind += hook.got; 4034196831Smav break; 403539214Sgibbs default: 403639214Sgibbs break; 403739214Sgibbs } 403839214Sgibbs } 403939214Sgibbs 404039214Sgibbs /* 404139214Sgibbs * If fd_data is set, and we're writing to the device, we need to 404239214Sgibbs * read the data the user wants written from stdin. 404339214Sgibbs */ 404439214Sgibbs if ((fd_data == 1) && (arglist & CAM_ARG_CMD_OUT)) { 4045102192Sjohan ssize_t amt_read; 404639214Sgibbs int amt_to_read = data_bytes; 404739214Sgibbs u_int8_t *buf_ptr = data_ptr; 404839214Sgibbs 404939214Sgibbs for (amt_read = 0; amt_to_read > 0; 405080381Ssheldonh amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) { 405139214Sgibbs if (amt_read == -1) { 405239214Sgibbs warn("error reading data from stdin"); 405339214Sgibbs error = 1; 405439214Sgibbs goto scsicmd_bailout; 405539214Sgibbs } 405639214Sgibbs amt_to_read -= amt_read; 405739214Sgibbs buf_ptr += amt_read; 405839214Sgibbs } 405939214Sgibbs } 406039214Sgibbs 406139214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 406239214Sgibbs flags |= CAM_PASS_ERR_RECOVER; 406339214Sgibbs 406439214Sgibbs /* Disable freezing the device queue */ 406539214Sgibbs flags |= CAM_DEV_QFRZDIS; 406639214Sgibbs 4067196831Smav if (cdb_len) { 4068196831Smav /* 4069196831Smav * This is taken from the SCSI-3 draft spec. 4070196831Smav * (T10/1157D revision 0.3) 4071196831Smav * The top 3 bits of an opcode are the group code. 4072196831Smav * The next 5 bits are the command code. 4073196831Smav * Group 0: six byte commands 4074196831Smav * Group 1: ten byte commands 4075196831Smav * Group 2: ten byte commands 4076196831Smav * Group 3: reserved 4077196831Smav * Group 4: sixteen byte commands 4078196831Smav * Group 5: twelve byte commands 4079196831Smav * Group 6: vendor specific 4080196831Smav * Group 7: vendor specific 4081196831Smav */ 4082196831Smav switch((cdb[0] >> 5) & 0x7) { 4083196831Smav case 0: 4084196831Smav cdb_len = 6; 4085196831Smav break; 4086196831Smav case 1: 4087196831Smav case 2: 4088196831Smav cdb_len = 10; 4089196831Smav break; 4090196831Smav case 3: 4091196831Smav case 6: 4092196831Smav case 7: 4093196831Smav /* computed by buff_encode_visit */ 4094196831Smav break; 4095196831Smav case 4: 4096196831Smav cdb_len = 16; 4097196831Smav break; 4098196831Smav case 5: 4099196831Smav cdb_len = 12; 4100196831Smav break; 4101196831Smav } 410239214Sgibbs 4103196831Smav /* 4104196831Smav * We should probably use csio_build_visit or something like that 4105196831Smav * here, but it's easier to encode arguments as you go. The 4106196831Smav * alternative would be skipping the CDB argument and then encoding 4107196831Smav * it here, since we've got the data buffer argument by now. 4108196831Smav */ 4109196831Smav bcopy(cdb, &ccb->csio.cdb_io.cdb_bytes, cdb_len); 411039214Sgibbs 4111196831Smav cam_fill_csio(&ccb->csio, 411239214Sgibbs /*retries*/ retry_count, 411339214Sgibbs /*cbfcnp*/ NULL, 411439214Sgibbs /*flags*/ flags, 411539214Sgibbs /*tag_action*/ MSG_SIMPLE_Q_TAG, 411639214Sgibbs /*data_ptr*/ data_ptr, 411739214Sgibbs /*dxfer_len*/ data_bytes, 411839214Sgibbs /*sense_len*/ SSD_FULL_SIZE, 411939214Sgibbs /*cdb_len*/ cdb_len, 412039214Sgibbs /*timeout*/ timeout ? timeout : 5000); 4121196831Smav } else { 4122196831Smav atacmd_len = 12; 4123196831Smav bcopy(atacmd, &ccb->ataio.cmd.command, atacmd_len); 4124196831Smav if (need_res) 4125196831Smav ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT; 4126207498Smav if (dmacmd) 4127207498Smav ccb->ataio.cmd.flags |= CAM_ATAIO_DMA; 4128207498Smav if (fpdmacmd) 4129207498Smav ccb->ataio.cmd.flags |= CAM_ATAIO_FPDMA; 413039214Sgibbs 4131196831Smav cam_fill_ataio(&ccb->ataio, 4132196831Smav /*retries*/ retry_count, 4133196831Smav /*cbfcnp*/ NULL, 4134196831Smav /*flags*/ flags, 4135196831Smav /*tag_action*/ 0, 4136196831Smav /*data_ptr*/ data_ptr, 4137196831Smav /*dxfer_len*/ data_bytes, 4138196831Smav /*timeout*/ timeout ? timeout : 5000); 4139196831Smav } 4140196831Smav 414139214Sgibbs if (((retval = cam_send_ccb(device, ccb)) < 0) 414239214Sgibbs || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 4143228602Sdim const char warnstr[] = "error sending command"; 4144216088Sken 414539214Sgibbs if (retval < 0) 4146216088Sken warn(warnstr); 414739214Sgibbs else 4148216088Sken warnx(warnstr); 414939214Sgibbs 415039214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 415174840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 415274840Sken CAM_EPF_ALL, stderr); 415339214Sgibbs } 415439214Sgibbs 415539214Sgibbs error = 1; 415639214Sgibbs goto scsicmd_bailout; 415739214Sgibbs } 415839214Sgibbs 4159196831Smav if (atacmd_len && need_res) { 4160196831Smav if (fd_res == 0) { 4161196831Smav buff_decode_visit(&ccb->ataio.res.status, 11, resstr, 4162196831Smav arg_put, NULL); 4163196831Smav fprintf(stdout, "\n"); 4164196831Smav } else { 4165196831Smav fprintf(stdout, 4166196831Smav "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", 4167196831Smav ccb->ataio.res.status, 4168196831Smav ccb->ataio.res.error, 4169196831Smav ccb->ataio.res.lba_low, 4170196831Smav ccb->ataio.res.lba_mid, 4171196831Smav ccb->ataio.res.lba_high, 4172196831Smav ccb->ataio.res.device, 4173196831Smav ccb->ataio.res.lba_low_exp, 4174196831Smav ccb->ataio.res.lba_mid_exp, 4175196831Smav ccb->ataio.res.lba_high_exp, 4176196831Smav ccb->ataio.res.sector_count, 4177196831Smav ccb->ataio.res.sector_count_exp); 4178196831Smav fflush(stdout); 4179196831Smav } 4180196831Smav } 418139214Sgibbs 418239214Sgibbs if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 418339214Sgibbs && (arglist & CAM_ARG_CMD_IN) 418439214Sgibbs && (data_bytes > 0)) { 418539214Sgibbs if (fd_data == 0) { 418639214Sgibbs buff_decode_visit(data_ptr, data_bytes, datastr, 418739214Sgibbs arg_put, NULL); 418839214Sgibbs fprintf(stdout, "\n"); 418939214Sgibbs } else { 4190102192Sjohan ssize_t amt_written; 419139214Sgibbs int amt_to_write = data_bytes; 419239214Sgibbs u_int8_t *buf_ptr = data_ptr; 419339214Sgibbs 419439214Sgibbs for (amt_written = 0; (amt_to_write > 0) && 419539214Sgibbs (amt_written =write(1, buf_ptr,amt_to_write))> 0;){ 419639214Sgibbs amt_to_write -= amt_written; 419739214Sgibbs buf_ptr += amt_written; 419839214Sgibbs } 419939214Sgibbs if (amt_written == -1) { 420039214Sgibbs warn("error writing data to stdout"); 420139214Sgibbs error = 1; 420239214Sgibbs goto scsicmd_bailout; 420339214Sgibbs } else if ((amt_written == 0) 420439214Sgibbs && (amt_to_write > 0)) { 420539214Sgibbs warnx("only wrote %u bytes out of %u", 420639214Sgibbs data_bytes - amt_to_write, data_bytes); 420739214Sgibbs } 420839214Sgibbs } 420939214Sgibbs } 421039214Sgibbs 421139214Sgibbsscsicmd_bailout: 421239214Sgibbs 421339214Sgibbs if ((data_bytes > 0) && (data_ptr != NULL)) 421439214Sgibbs free(data_ptr); 421539214Sgibbs 421639214Sgibbs cam_freeccb(ccb); 421739214Sgibbs 421839214Sgibbs return(error); 421939214Sgibbs} 422039214Sgibbs 422139214Sgibbsstatic int 422239214Sgibbscamdebug(int argc, char **argv, char *combinedopt) 422339214Sgibbs{ 422439214Sgibbs int c, fd; 4225260509Smav path_id_t bus = CAM_BUS_WILDCARD; 4226260509Smav target_id_t target = CAM_TARGET_WILDCARD; 4227260509Smav lun_id_t lun = CAM_LUN_WILDCARD; 422839214Sgibbs char *tstr, *tmpstr = NULL; 422939214Sgibbs union ccb ccb; 423039214Sgibbs int error = 0; 423139214Sgibbs 423239214Sgibbs bzero(&ccb, sizeof(union ccb)); 423339214Sgibbs 423439214Sgibbs while ((c = getopt(argc, argv, combinedopt)) != -1) { 423539214Sgibbs switch(c) { 423639214Sgibbs case 'I': 423739214Sgibbs arglist |= CAM_ARG_DEBUG_INFO; 423839214Sgibbs ccb.cdbg.flags |= CAM_DEBUG_INFO; 423939214Sgibbs break; 4240107966Snjl case 'P': 4241107966Snjl arglist |= CAM_ARG_DEBUG_PERIPH; 4242107966Snjl ccb.cdbg.flags |= CAM_DEBUG_PERIPH; 4243107966Snjl break; 424452541Sluoqi case 'S': 424552541Sluoqi arglist |= CAM_ARG_DEBUG_SUBTRACE; 424652541Sluoqi ccb.cdbg.flags |= CAM_DEBUG_SUBTRACE; 424752541Sluoqi break; 424852535Sluoqi case 'T': 424939214Sgibbs arglist |= CAM_ARG_DEBUG_TRACE; 425039214Sgibbs ccb.cdbg.flags |= CAM_DEBUG_TRACE; 425139214Sgibbs break; 4252107966Snjl case 'X': 4253107966Snjl arglist |= CAM_ARG_DEBUG_XPT; 4254107966Snjl ccb.cdbg.flags |= CAM_DEBUG_XPT; 4255107966Snjl break; 425639903Sken case 'c': 425739903Sken arglist |= CAM_ARG_DEBUG_CDB; 425839903Sken ccb.cdbg.flags |= CAM_DEBUG_CDB; 425939903Sken break; 4260236555Smav case 'p': 4261236555Smav arglist |= CAM_ARG_DEBUG_PROBE; 4262236555Smav ccb.cdbg.flags |= CAM_DEBUG_PROBE; 4263236555Smav break; 426439214Sgibbs default: 426539214Sgibbs break; 426639214Sgibbs } 426739214Sgibbs } 426839214Sgibbs 426939214Sgibbs if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { 427039214Sgibbs warnx("error opening transport layer device %s", XPT_DEVICE); 427139214Sgibbs warn("%s", XPT_DEVICE); 427239214Sgibbs return(1); 427339214Sgibbs } 427439214Sgibbs argc -= optind; 427539214Sgibbs argv += optind; 427639214Sgibbs 427739214Sgibbs if (argc <= 0) { 427839214Sgibbs warnx("you must specify \"off\", \"all\" or a bus,"); 427939214Sgibbs warnx("bus:target, or bus:target:lun"); 428039214Sgibbs close(fd); 428139214Sgibbs return(1); 428239214Sgibbs } 428339214Sgibbs 428439214Sgibbs tstr = *argv; 428539214Sgibbs 428639214Sgibbs while (isspace(*tstr) && (*tstr != '\0')) 428739214Sgibbs tstr++; 428839214Sgibbs 428939214Sgibbs if (strncmp(tstr, "off", 3) == 0) { 429039214Sgibbs ccb.cdbg.flags = CAM_DEBUG_NONE; 4291107966Snjl arglist &= ~(CAM_ARG_DEBUG_INFO|CAM_ARG_DEBUG_PERIPH| 4292107966Snjl CAM_ARG_DEBUG_TRACE|CAM_ARG_DEBUG_SUBTRACE| 4293236555Smav CAM_ARG_DEBUG_XPT|CAM_ARG_DEBUG_PROBE); 429439214Sgibbs } else if (strncmp(tstr, "all", 3) != 0) { 429539214Sgibbs tmpstr = (char *)strtok(tstr, ":"); 429639214Sgibbs if ((tmpstr != NULL) && (*tmpstr != '\0')){ 429739214Sgibbs bus = strtol(tmpstr, NULL, 0); 429839214Sgibbs arglist |= CAM_ARG_BUS; 429939214Sgibbs tmpstr = (char *)strtok(NULL, ":"); 430039214Sgibbs if ((tmpstr != NULL) && (*tmpstr != '\0')){ 430139214Sgibbs target = strtol(tmpstr, NULL, 0); 430239214Sgibbs arglist |= CAM_ARG_TARGET; 430339214Sgibbs tmpstr = (char *)strtok(NULL, ":"); 430439214Sgibbs if ((tmpstr != NULL) && (*tmpstr != '\0')){ 430539214Sgibbs lun = strtol(tmpstr, NULL, 0); 430639214Sgibbs arglist |= CAM_ARG_LUN; 430739214Sgibbs } 430839214Sgibbs } 430939214Sgibbs } else { 431039214Sgibbs error = 1; 431139214Sgibbs warnx("you must specify \"all\", \"off\", or a bus,"); 431239214Sgibbs warnx("bus:target, or bus:target:lun to debug"); 431339214Sgibbs } 431439214Sgibbs } 4315214321Smav 431639214Sgibbs if (error == 0) { 431739214Sgibbs 431839214Sgibbs ccb.ccb_h.func_code = XPT_DEBUG; 431939214Sgibbs ccb.ccb_h.path_id = bus; 432039214Sgibbs ccb.ccb_h.target_id = target; 432139214Sgibbs ccb.ccb_h.target_lun = lun; 432239214Sgibbs 432339214Sgibbs if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 432439214Sgibbs warn("CAMIOCOMMAND ioctl failed"); 432539214Sgibbs error = 1; 432639214Sgibbs } 432739214Sgibbs 432839214Sgibbs if (error == 0) { 432939214Sgibbs if ((ccb.ccb_h.status & CAM_STATUS_MASK) == 433039214Sgibbs CAM_FUNC_NOTAVAIL) { 433139214Sgibbs warnx("CAM debugging not available"); 433239214Sgibbs warnx("you need to put options CAMDEBUG in" 433339214Sgibbs " your kernel config file!"); 433439214Sgibbs error = 1; 433539214Sgibbs } else if ((ccb.ccb_h.status & CAM_STATUS_MASK) != 433639214Sgibbs CAM_REQ_CMP) { 433739214Sgibbs warnx("XPT_DEBUG CCB failed with status %#x", 433839214Sgibbs ccb.ccb_h.status); 433939214Sgibbs error = 1; 434039214Sgibbs } else { 434139214Sgibbs if (ccb.cdbg.flags == CAM_DEBUG_NONE) { 434239214Sgibbs fprintf(stderr, 434339214Sgibbs "Debugging turned off\n"); 434439214Sgibbs } else { 434539214Sgibbs fprintf(stderr, 434639214Sgibbs "Debugging enabled for " 4347260509Smav "%d:%d:%jx\n", 4348260509Smav bus, target, (uintmax_t)lun); 434939214Sgibbs } 435039214Sgibbs } 435139214Sgibbs } 435239903Sken close(fd); 435339214Sgibbs } 435439214Sgibbs 435539214Sgibbs return(error); 435639214Sgibbs} 435739214Sgibbs 435846581Skenstatic int 435946581Skentagcontrol(struct cam_device *device, int argc, char **argv, 436046581Sken char *combinedopt) 436146581Sken{ 436246581Sken int c; 436346581Sken union ccb *ccb; 436446581Sken int numtags = -1; 436546581Sken int retval = 0; 436646581Sken int quiet = 0; 436746581Sken char pathstr[1024]; 436846581Sken 436946581Sken ccb = cam_getccb(device); 437046581Sken 437146581Sken if (ccb == NULL) { 437246581Sken warnx("tagcontrol: error allocating ccb"); 437346581Sken return(1); 437446581Sken } 437546581Sken 437646581Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 437746581Sken switch(c) { 437846581Sken case 'N': 437946581Sken numtags = strtol(optarg, NULL, 0); 438046581Sken if (numtags < 0) { 438146581Sken warnx("tag count %d is < 0", numtags); 438246581Sken retval = 1; 438346581Sken goto tagcontrol_bailout; 438446581Sken } 438546581Sken break; 438646581Sken case 'q': 438746581Sken quiet++; 438846581Sken break; 438946581Sken default: 439046581Sken break; 439146581Sken } 439246581Sken } 439346581Sken 439446581Sken cam_path_string(device, pathstr, sizeof(pathstr)); 439546581Sken 439646581Sken if (numtags >= 0) { 439746581Sken bzero(&(&ccb->ccb_h)[1], 439846581Sken sizeof(struct ccb_relsim) - sizeof(struct ccb_hdr)); 439946581Sken ccb->ccb_h.func_code = XPT_REL_SIMQ; 4400220887Smav ccb->ccb_h.flags = CAM_DEV_QFREEZE; 440146581Sken ccb->crs.release_flags = RELSIM_ADJUST_OPENINGS; 440246581Sken ccb->crs.openings = numtags; 440346581Sken 440446581Sken 440546581Sken if (cam_send_ccb(device, ccb) < 0) { 440646581Sken perror("error sending XPT_REL_SIMQ CCB"); 440746581Sken retval = 1; 440846581Sken goto tagcontrol_bailout; 440946581Sken } 441046581Sken 441146581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 441274840Sken warnx("XPT_REL_SIMQ CCB failed"); 441374840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 441474840Sken CAM_EPF_ALL, stderr); 441546581Sken retval = 1; 441646581Sken goto tagcontrol_bailout; 441746581Sken } 441846581Sken 441946581Sken 442046581Sken if (quiet == 0) 442146581Sken fprintf(stdout, "%stagged openings now %d\n", 442246581Sken pathstr, ccb->crs.openings); 442346581Sken } 442446581Sken 442546581Sken bzero(&(&ccb->ccb_h)[1], 442693501Sken sizeof(struct ccb_getdevstats) - sizeof(struct ccb_hdr)); 442746581Sken 442856121Smjacob ccb->ccb_h.func_code = XPT_GDEV_STATS; 442946581Sken 443046581Sken if (cam_send_ccb(device, ccb) < 0) { 443156121Smjacob perror("error sending XPT_GDEV_STATS CCB"); 443246581Sken retval = 1; 443346581Sken goto tagcontrol_bailout; 443446581Sken } 443546581Sken 443646581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 443774840Sken warnx("XPT_GDEV_STATS CCB failed"); 443874840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 443974840Sken CAM_EPF_ALL, stderr); 444046581Sken retval = 1; 444146581Sken goto tagcontrol_bailout; 444246581Sken } 444346581Sken 444446581Sken if (arglist & CAM_ARG_VERBOSE) { 444546581Sken fprintf(stdout, "%s", pathstr); 444656121Smjacob fprintf(stdout, "dev_openings %d\n", ccb->cgds.dev_openings); 444746581Sken fprintf(stdout, "%s", pathstr); 444856121Smjacob fprintf(stdout, "dev_active %d\n", ccb->cgds.dev_active); 444946581Sken fprintf(stdout, "%s", pathstr); 445056121Smjacob fprintf(stdout, "devq_openings %d\n", ccb->cgds.devq_openings); 445146581Sken fprintf(stdout, "%s", pathstr); 445256121Smjacob fprintf(stdout, "devq_queued %d\n", ccb->cgds.devq_queued); 445346581Sken fprintf(stdout, "%s", pathstr); 445456121Smjacob fprintf(stdout, "held %d\n", ccb->cgds.held); 445546581Sken fprintf(stdout, "%s", pathstr); 445656121Smjacob fprintf(stdout, "mintags %d\n", ccb->cgds.mintags); 445746581Sken fprintf(stdout, "%s", pathstr); 445856121Smjacob fprintf(stdout, "maxtags %d\n", ccb->cgds.maxtags); 445946581Sken } else { 446046581Sken if (quiet == 0) { 446146581Sken fprintf(stdout, "%s", pathstr); 446246581Sken fprintf(stdout, "device openings: "); 446346581Sken } 446456121Smjacob fprintf(stdout, "%d\n", ccb->cgds.dev_openings + 446556121Smjacob ccb->cgds.dev_active); 446646581Sken } 446746581Sken 446846581Skentagcontrol_bailout: 446946581Sken 447046581Sken cam_freeccb(ccb); 447146581Sken return(retval); 447246581Sken} 447346581Sken 447446581Skenstatic void 447546581Skencts_print(struct cam_device *device, struct ccb_trans_settings *cts) 447646581Sken{ 447746581Sken char pathstr[1024]; 447846581Sken 447946581Sken cam_path_string(device, pathstr, sizeof(pathstr)); 448046581Sken 4481163896Smjacob if (cts->transport == XPORT_SPI) { 4482163896Smjacob struct ccb_trans_settings_spi *spi = 4483163896Smjacob &cts->xport_specific.spi; 448446581Sken 4485163896Smjacob if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) { 448646581Sken 4487163896Smjacob fprintf(stdout, "%ssync parameter: %d\n", pathstr, 4488163896Smjacob spi->sync_period); 448946581Sken 4490163896Smjacob if (spi->sync_offset != 0) { 4491163896Smjacob u_int freq; 4492163896Smjacob 4493163896Smjacob freq = scsi_calc_syncsrate(spi->sync_period); 4494163896Smjacob fprintf(stdout, "%sfrequency: %d.%03dMHz\n", 4495163896Smjacob pathstr, freq / 1000, freq % 1000); 4496163896Smjacob } 449746581Sken } 449846581Sken 4499163896Smjacob if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) { 4500163896Smjacob fprintf(stdout, "%soffset: %d\n", pathstr, 4501163896Smjacob spi->sync_offset); 4502163896Smjacob } 450346581Sken 4504163896Smjacob if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) { 4505163896Smjacob fprintf(stdout, "%sbus width: %d bits\n", pathstr, 4506163896Smjacob (0x01 << spi->bus_width) * 8); 4507163896Smjacob } 450846581Sken 4509163896Smjacob if (spi->valid & CTS_SPI_VALID_DISC) { 4510163896Smjacob fprintf(stdout, "%sdisconnection is %s\n", pathstr, 4511163896Smjacob (spi->flags & CTS_SPI_FLAGS_DISC_ENB) ? 4512163896Smjacob "enabled" : "disabled"); 4513163896Smjacob } 4514163896Smjacob } 4515236437Smav if (cts->transport == XPORT_FC) { 4516236437Smav struct ccb_trans_settings_fc *fc = 4517236437Smav &cts->xport_specific.fc; 4518236437Smav 4519236437Smav if (fc->valid & CTS_FC_VALID_WWNN) 4520254954Smav fprintf(stdout, "%sWWNN: 0x%llx\n", pathstr, 4521236437Smav (long long) fc->wwnn); 4522236437Smav if (fc->valid & CTS_FC_VALID_WWPN) 4523254954Smav fprintf(stdout, "%sWWPN: 0x%llx\n", pathstr, 4524236437Smav (long long) fc->wwpn); 4525236437Smav if (fc->valid & CTS_FC_VALID_PORT) 4526254954Smav fprintf(stdout, "%sPortID: 0x%x\n", pathstr, fc->port); 4527236437Smav if (fc->valid & CTS_FC_VALID_SPEED) 4528236437Smav fprintf(stdout, "%stransfer speed: %d.%03dMB/s\n", 4529236437Smav pathstr, fc->bitrate / 1000, fc->bitrate % 1000); 4530236437Smav } 4531236437Smav if (cts->transport == XPORT_SAS) { 4532236437Smav struct ccb_trans_settings_sas *sas = 4533236437Smav &cts->xport_specific.sas; 4534236437Smav 4535236437Smav if (sas->valid & CTS_SAS_VALID_SPEED) 4536236437Smav fprintf(stdout, "%stransfer speed: %d.%03dMB/s\n", 4537236437Smav pathstr, sas->bitrate / 1000, sas->bitrate % 1000); 4538236437Smav } 4539199747Smav if (cts->transport == XPORT_ATA) { 4540236437Smav struct ccb_trans_settings_pata *pata = 4541199747Smav &cts->xport_specific.ata; 454246581Sken 4543236437Smav if ((pata->valid & CTS_ATA_VALID_MODE) != 0) { 4544199747Smav fprintf(stdout, "%sATA mode: %s\n", pathstr, 4545236437Smav ata_mode2string(pata->mode)); 4546199747Smav } 4547236437Smav if ((pata->valid & CTS_ATA_VALID_ATAPI) != 0) { 4548203376Smav fprintf(stdout, "%sATAPI packet length: %d\n", pathstr, 4549236437Smav pata->atapi); 4550203376Smav } 4551236437Smav if ((pata->valid & CTS_ATA_VALID_BYTECOUNT) != 0) { 4552199747Smav fprintf(stdout, "%sPIO transaction length: %d\n", 4553236437Smav pathstr, pata->bytecount); 4554199747Smav } 4555199747Smav } 4556199747Smav if (cts->transport == XPORT_SATA) { 4557199747Smav struct ccb_trans_settings_sata *sata = 4558199747Smav &cts->xport_specific.sata; 4559199747Smav 4560199747Smav if ((sata->valid & CTS_SATA_VALID_REVISION) != 0) { 4561199747Smav fprintf(stdout, "%sSATA revision: %d.x\n", pathstr, 4562199747Smav sata->revision); 4563199747Smav } 4564199747Smav if ((sata->valid & CTS_SATA_VALID_MODE) != 0) { 4565199747Smav fprintf(stdout, "%sATA mode: %s\n", pathstr, 4566199747Smav ata_mode2string(sata->mode)); 4567199747Smav } 4568203376Smav if ((sata->valid & CTS_SATA_VALID_ATAPI) != 0) { 4569203376Smav fprintf(stdout, "%sATAPI packet length: %d\n", pathstr, 4570203376Smav sata->atapi); 4571203376Smav } 4572199747Smav if ((sata->valid & CTS_SATA_VALID_BYTECOUNT) != 0) { 4573199747Smav fprintf(stdout, "%sPIO transaction length: %d\n", 4574199747Smav pathstr, sata->bytecount); 4575199747Smav } 4576199747Smav if ((sata->valid & CTS_SATA_VALID_PM) != 0) { 4577199747Smav fprintf(stdout, "%sPMP presence: %d\n", pathstr, 4578199747Smav sata->pm_present); 4579199747Smav } 4580199747Smav if ((sata->valid & CTS_SATA_VALID_TAGS) != 0) { 4581199747Smav fprintf(stdout, "%sNumber of tags: %d\n", pathstr, 4582199747Smav sata->tags); 4583199747Smav } 4584207499Smav if ((sata->valid & CTS_SATA_VALID_CAPS) != 0) { 4585207499Smav fprintf(stdout, "%sSATA capabilities: %08x\n", pathstr, 4586207499Smav sata->caps); 4587207499Smav } 4588199747Smav } 4589236437Smav if (cts->protocol == PROTO_ATA) { 4590236437Smav struct ccb_trans_settings_ata *ata= 4591236437Smav &cts->proto_specific.ata; 4592236437Smav 4593236437Smav if (ata->valid & CTS_ATA_VALID_TQ) { 4594236437Smav fprintf(stdout, "%stagged queueing: %s\n", pathstr, 4595236437Smav (ata->flags & CTS_ATA_FLAGS_TAG_ENB) ? 4596236437Smav "enabled" : "disabled"); 4597236437Smav } 4598236437Smav } 4599163896Smjacob if (cts->protocol == PROTO_SCSI) { 4600163896Smjacob struct ccb_trans_settings_scsi *scsi= 4601163896Smjacob &cts->proto_specific.scsi; 460246581Sken 4603163896Smjacob if (scsi->valid & CTS_SCSI_VALID_TQ) { 4604236437Smav fprintf(stdout, "%stagged queueing: %s\n", pathstr, 4605163896Smjacob (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) ? 4606163896Smjacob "enabled" : "disabled"); 4607163896Smjacob } 4608163896Smjacob } 4609163896Smjacob 461046581Sken} 461146581Sken 461246581Sken/* 4613214321Smav * Get a path inquiry CCB for the specified device. 461446581Sken */ 461546581Skenstatic int 461646581Skenget_cpi(struct cam_device *device, struct ccb_pathinq *cpi) 461746581Sken{ 461846581Sken union ccb *ccb; 461946581Sken int retval = 0; 462046581Sken 462146581Sken ccb = cam_getccb(device); 462246581Sken if (ccb == NULL) { 462346581Sken warnx("get_cpi: couldn't allocate CCB"); 462446581Sken return(1); 462546581Sken } 462646581Sken bzero(&(&ccb->ccb_h)[1], 462746581Sken sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr)); 462846581Sken ccb->ccb_h.func_code = XPT_PATH_INQ; 462946581Sken if (cam_send_ccb(device, ccb) < 0) { 463046581Sken warn("get_cpi: error sending Path Inquiry CCB"); 463146581Sken if (arglist & CAM_ARG_VERBOSE) 463274840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 463374840Sken CAM_EPF_ALL, stderr); 463446581Sken retval = 1; 463546581Sken goto get_cpi_bailout; 463646581Sken } 463746581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 463846581Sken if (arglist & CAM_ARG_VERBOSE) 463974840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 464074840Sken CAM_EPF_ALL, stderr); 464146581Sken retval = 1; 464246581Sken goto get_cpi_bailout; 464346581Sken } 464446581Sken bcopy(&ccb->cpi, cpi, sizeof(struct ccb_pathinq)); 464546581Sken 464646581Skenget_cpi_bailout: 4647196658Smav cam_freeccb(ccb); 4648196658Smav return(retval); 4649196658Smav} 465046581Sken 4651196658Smav/* 4652214321Smav * Get a get device CCB for the specified device. 4653196658Smav */ 4654196658Smavstatic int 4655196658Smavget_cgd(struct cam_device *device, struct ccb_getdev *cgd) 4656196658Smav{ 4657196658Smav union ccb *ccb; 4658196658Smav int retval = 0; 4659196658Smav 4660196658Smav ccb = cam_getccb(device); 4661196658Smav if (ccb == NULL) { 4662196658Smav warnx("get_cgd: couldn't allocate CCB"); 4663196658Smav return(1); 4664196658Smav } 4665196658Smav bzero(&(&ccb->ccb_h)[1], 4666196658Smav sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr)); 4667196658Smav ccb->ccb_h.func_code = XPT_GDEV_TYPE; 4668196658Smav if (cam_send_ccb(device, ccb) < 0) { 4669196658Smav warn("get_cgd: error sending Path Inquiry CCB"); 4670196658Smav if (arglist & CAM_ARG_VERBOSE) 4671196658Smav cam_error_print(device, ccb, CAM_ESF_ALL, 4672196658Smav CAM_EPF_ALL, stderr); 4673196658Smav retval = 1; 4674196658Smav goto get_cgd_bailout; 4675196658Smav } 4676196658Smav if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 4677196658Smav if (arglist & CAM_ARG_VERBOSE) 4678196658Smav cam_error_print(device, ccb, CAM_ESF_ALL, 4679196658Smav CAM_EPF_ALL, stderr); 4680196658Smav retval = 1; 4681196658Smav goto get_cgd_bailout; 4682196658Smav } 4683196658Smav bcopy(&ccb->cgd, cgd, sizeof(struct ccb_getdev)); 4684196658Smav 4685196658Smavget_cgd_bailout: 468646581Sken cam_freeccb(ccb); 468746581Sken return(retval); 468846581Sken} 468946581Sken 4690237281Sscottl/* return the type of disk (really the command type) */ 4691237281Sscottlstatic const char * 4692237281Sscottlget_disk_type(struct cam_device *device) 4693237281Sscottl{ 4694237281Sscottl struct ccb_getdev cgd; 4695237281Sscottl 4696237281Sscottl (void) memset(&cgd, 0x0, sizeof(cgd)); 4697237281Sscottl get_cgd(device, &cgd); 4698237281Sscottl switch(cgd.protocol) { 4699237281Sscottl case PROTO_SCSI: 4700237281Sscottl return "scsi"; 4701237281Sscottl case PROTO_ATA: 4702237281Sscottl case PROTO_ATAPI: 4703237281Sscottl case PROTO_SATAPM: 4704237281Sscottl return "ata"; 4705237281Sscottl default: 4706237281Sscottl return "unknown"; 4707237281Sscottl } 4708237281Sscottl} 4709237281Sscottl 471046581Skenstatic void 471146581Skencpi_print(struct ccb_pathinq *cpi) 471246581Sken{ 471346581Sken char adapter_str[1024]; 471446581Sken int i; 471546581Sken 471646581Sken snprintf(adapter_str, sizeof(adapter_str), 471746581Sken "%s%d:", cpi->dev_name, cpi->unit_number); 471846581Sken 471946581Sken fprintf(stdout, "%s SIM/HBA version: %d\n", adapter_str, 472046581Sken cpi->version_num); 472146581Sken 472246581Sken for (i = 1; i < 0xff; i = i << 1) { 4723118478Sjohan const char *str; 472446581Sken 472546581Sken if ((i & cpi->hba_inquiry) == 0) 472646581Sken continue; 472746581Sken 472846581Sken fprintf(stdout, "%s supports ", adapter_str); 472946581Sken 473046581Sken switch(i) { 473146581Sken case PI_MDP_ABLE: 473246581Sken str = "MDP message"; 473346581Sken break; 473446581Sken case PI_WIDE_32: 473546581Sken str = "32 bit wide SCSI"; 473646581Sken break; 473746581Sken case PI_WIDE_16: 473846581Sken str = "16 bit wide SCSI"; 473946581Sken break; 474046581Sken case PI_SDTR_ABLE: 474146581Sken str = "SDTR message"; 474246581Sken break; 474346581Sken case PI_LINKED_CDB: 474446581Sken str = "linked CDBs"; 474546581Sken break; 474646581Sken case PI_TAG_ABLE: 474746581Sken str = "tag queue messages"; 474846581Sken break; 474946581Sken case PI_SOFT_RST: 475046581Sken str = "soft reset alternative"; 475146581Sken break; 4752196658Smav case PI_SATAPM: 4753196658Smav str = "SATA Port Multiplier"; 4754196658Smav break; 475551691Sbillf default: 475651691Sbillf str = "unknown PI bit set"; 475751691Sbillf break; 475846581Sken } 475946581Sken fprintf(stdout, "%s\n", str); 476046581Sken } 476146581Sken 476246581Sken for (i = 1; i < 0xff; i = i << 1) { 4763118478Sjohan const char *str; 476446581Sken 476546581Sken if ((i & cpi->hba_misc) == 0) 476646581Sken continue; 476746581Sken 476846581Sken fprintf(stdout, "%s ", adapter_str); 476946581Sken 477046581Sken switch(i) { 477146581Sken case PIM_SCANHILO: 477246581Sken str = "bus scans from high ID to low ID"; 477346581Sken break; 477446581Sken case PIM_NOREMOVE: 477546581Sken str = "removable devices not included in scan"; 477646581Sken break; 477746581Sken case PIM_NOINITIATOR: 477846581Sken str = "initiator role not supported"; 477946581Sken break; 478046581Sken case PIM_NOBUSRESET: 478146581Sken str = "user has disabled initial BUS RESET or" 478246581Sken " controller is in target/mixed mode"; 478346581Sken break; 4784196658Smav case PIM_NO_6_BYTE: 4785196658Smav str = "do not send 6-byte commands"; 4786196658Smav break; 4787196658Smav case PIM_SEQSCAN: 4788196658Smav str = "scan bus sequentially"; 4789196658Smav break; 479051691Sbillf default: 479151691Sbillf str = "unknown PIM bit set"; 479251691Sbillf break; 479346581Sken } 479446581Sken fprintf(stdout, "%s\n", str); 479546581Sken } 479646581Sken 479746581Sken for (i = 1; i < 0xff; i = i << 1) { 4798118478Sjohan const char *str; 479946581Sken 480046581Sken if ((i & cpi->target_sprt) == 0) 480146581Sken continue; 480246581Sken 480346581Sken fprintf(stdout, "%s supports ", adapter_str); 480446581Sken switch(i) { 480546581Sken case PIT_PROCESSOR: 480646581Sken str = "target mode processor mode"; 480746581Sken break; 480846581Sken case PIT_PHASE: 480946581Sken str = "target mode phase cog. mode"; 481046581Sken break; 481146581Sken case PIT_DISCONNECT: 481246581Sken str = "disconnects in target mode"; 481346581Sken break; 481446581Sken case PIT_TERM_IO: 481546581Sken str = "terminate I/O message in target mode"; 481646581Sken break; 481746581Sken case PIT_GRP_6: 481846581Sken str = "group 6 commands in target mode"; 481946581Sken break; 482046581Sken case PIT_GRP_7: 482146581Sken str = "group 7 commands in target mode"; 482246581Sken break; 482351691Sbillf default: 482451691Sbillf str = "unknown PIT bit set"; 482551691Sbillf break; 482646581Sken } 482746581Sken 482846581Sken fprintf(stdout, "%s\n", str); 482946581Sken } 483046581Sken fprintf(stdout, "%s HBA engine count: %d\n", adapter_str, 483146581Sken cpi->hba_eng_cnt); 483256985Sken fprintf(stdout, "%s maximum target: %d\n", adapter_str, 483346581Sken cpi->max_target); 483456985Sken fprintf(stdout, "%s maximum LUN: %d\n", adapter_str, 483546581Sken cpi->max_lun); 483646581Sken fprintf(stdout, "%s highest path ID in subsystem: %d\n", 483746581Sken adapter_str, cpi->hpath_id); 483866003Sken fprintf(stdout, "%s initiator ID: %d\n", adapter_str, 483966003Sken cpi->initiator_id); 484046581Sken fprintf(stdout, "%s SIM vendor: %s\n", adapter_str, cpi->sim_vid); 484146581Sken fprintf(stdout, "%s HBA vendor: %s\n", adapter_str, cpi->hba_vid); 4842210471Smav fprintf(stdout, "%s HBA vendor ID: 0x%04x\n", 4843210471Smav adapter_str, cpi->hba_vendor); 4844210471Smav fprintf(stdout, "%s HBA device ID: 0x%04x\n", 4845210471Smav adapter_str, cpi->hba_device); 4846210471Smav fprintf(stdout, "%s HBA subvendor ID: 0x%04x\n", 4847210471Smav adapter_str, cpi->hba_subvendor); 4848210471Smav fprintf(stdout, "%s HBA subdevice ID: 0x%04x\n", 4849210471Smav adapter_str, cpi->hba_subdevice); 485046581Sken fprintf(stdout, "%s bus ID: %d\n", adapter_str, cpi->bus_id); 485146581Sken fprintf(stdout, "%s base transfer speed: ", adapter_str); 485246581Sken if (cpi->base_transfer_speed > 1000) 485346581Sken fprintf(stdout, "%d.%03dMB/sec\n", 485446581Sken cpi->base_transfer_speed / 1000, 485546581Sken cpi->base_transfer_speed % 1000); 485646581Sken else 485746581Sken fprintf(stdout, "%dKB/sec\n", 485846581Sken (cpi->base_transfer_speed % 1000) * 1000); 4859210471Smav fprintf(stdout, "%s maximum transfer size: %u bytes\n", 4860210471Smav adapter_str, cpi->maxio); 486146581Sken} 486246581Sken 486346581Skenstatic int 486446581Skenget_print_cts(struct cam_device *device, int user_settings, int quiet, 486546581Sken struct ccb_trans_settings *cts) 486646581Sken{ 486746581Sken int retval; 486846581Sken union ccb *ccb; 486946581Sken 487046581Sken retval = 0; 487146581Sken ccb = cam_getccb(device); 487246581Sken 487346581Sken if (ccb == NULL) { 487446581Sken warnx("get_print_cts: error allocating ccb"); 487546581Sken return(1); 487646581Sken } 487746581Sken 487846581Sken bzero(&(&ccb->ccb_h)[1], 487946581Sken sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr)); 488046581Sken 488146581Sken ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 488246581Sken 488346581Sken if (user_settings == 0) 4884163896Smjacob ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS; 488546581Sken else 4886163896Smjacob ccb->cts.type = CTS_TYPE_USER_SETTINGS; 488746581Sken 488846581Sken if (cam_send_ccb(device, ccb) < 0) { 488946581Sken perror("error sending XPT_GET_TRAN_SETTINGS CCB"); 489074840Sken if (arglist & CAM_ARG_VERBOSE) 489174840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 489274840Sken CAM_EPF_ALL, stderr); 489346581Sken retval = 1; 489446581Sken goto get_print_cts_bailout; 489546581Sken } 489646581Sken 489746581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 489874840Sken warnx("XPT_GET_TRANS_SETTINGS CCB failed"); 489974840Sken if (arglist & CAM_ARG_VERBOSE) 490074840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 490174840Sken CAM_EPF_ALL, stderr); 490246581Sken retval = 1; 490346581Sken goto get_print_cts_bailout; 490446581Sken } 490546581Sken 490646581Sken if (quiet == 0) 490746581Sken cts_print(device, &ccb->cts); 490846581Sken 490946581Sken if (cts != NULL) 491046581Sken bcopy(&ccb->cts, cts, sizeof(struct ccb_trans_settings)); 491146581Sken 491246581Skenget_print_cts_bailout: 491346581Sken 491446581Sken cam_freeccb(ccb); 491546581Sken 491646581Sken return(retval); 491746581Sken} 491846581Sken 491946581Skenstatic int 492046581Skenratecontrol(struct cam_device *device, int retry_count, int timeout, 492146581Sken int argc, char **argv, char *combinedopt) 492246581Sken{ 492346581Sken int c; 492446581Sken union ccb *ccb; 492546581Sken int user_settings = 0; 492646581Sken int retval = 0; 492746581Sken int disc_enable = -1, tag_enable = -1; 4928199821Smav int mode = -1; 492946581Sken int offset = -1; 493046581Sken double syncrate = -1; 493146581Sken int bus_width = -1; 493246581Sken int quiet = 0; 493346581Sken int change_settings = 0, send_tur = 0; 493446581Sken struct ccb_pathinq cpi; 493546581Sken 493646581Sken ccb = cam_getccb(device); 493746581Sken if (ccb == NULL) { 493846581Sken warnx("ratecontrol: error allocating ccb"); 493946581Sken return(1); 494046581Sken } 494146581Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 494246581Sken switch(c){ 494346581Sken case 'a': 494446581Sken send_tur = 1; 494546581Sken break; 494646581Sken case 'c': 494746581Sken user_settings = 0; 494846581Sken break; 494946581Sken case 'D': 495046581Sken if (strncasecmp(optarg, "enable", 6) == 0) 495146581Sken disc_enable = 1; 495246581Sken else if (strncasecmp(optarg, "disable", 7) == 0) 495346581Sken disc_enable = 0; 495446581Sken else { 495546581Sken warnx("-D argument \"%s\" is unknown", optarg); 495646581Sken retval = 1; 495746581Sken goto ratecontrol_bailout; 495846581Sken } 495946581Sken change_settings = 1; 496046581Sken break; 4961199821Smav case 'M': 4962199821Smav mode = ata_string2mode(optarg); 4963199821Smav if (mode < 0) { 4964199821Smav warnx("unknown mode '%s'", optarg); 4965199821Smav retval = 1; 4966199821Smav goto ratecontrol_bailout; 4967199821Smav } 4968199821Smav change_settings = 1; 4969199821Smav break; 497046581Sken case 'O': 497146581Sken offset = strtol(optarg, NULL, 0); 497246581Sken if (offset < 0) { 497346581Sken warnx("offset value %d is < 0", offset); 497446581Sken retval = 1; 497546581Sken goto ratecontrol_bailout; 497646581Sken } 497746581Sken change_settings = 1; 497846581Sken break; 497946581Sken case 'q': 498046581Sken quiet++; 498146581Sken break; 498246581Sken case 'R': 498346581Sken syncrate = atof(optarg); 498446581Sken if (syncrate < 0) { 498546581Sken warnx("sync rate %f is < 0", syncrate); 498646581Sken retval = 1; 498746581Sken goto ratecontrol_bailout; 498846581Sken } 498946581Sken change_settings = 1; 499046581Sken break; 499146581Sken case 'T': 499246581Sken if (strncasecmp(optarg, "enable", 6) == 0) 499346581Sken tag_enable = 1; 499446581Sken else if (strncasecmp(optarg, "disable", 7) == 0) 499546581Sken tag_enable = 0; 499646581Sken else { 499746581Sken warnx("-T argument \"%s\" is unknown", optarg); 499846581Sken retval = 1; 499946581Sken goto ratecontrol_bailout; 500046581Sken } 500146581Sken change_settings = 1; 500246581Sken break; 500346581Sken case 'U': 500446581Sken user_settings = 1; 500546581Sken break; 500646581Sken case 'W': 500746581Sken bus_width = strtol(optarg, NULL, 0); 500846581Sken if (bus_width < 0) { 500946581Sken warnx("bus width %d is < 0", bus_width); 501046581Sken retval = 1; 501146581Sken goto ratecontrol_bailout; 501246581Sken } 501346581Sken change_settings = 1; 501446581Sken break; 501546581Sken default: 501646581Sken break; 501746581Sken } 501846581Sken } 501946581Sken bzero(&(&ccb->ccb_h)[1], 502046581Sken sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr)); 502146581Sken /* 502246581Sken * Grab path inquiry information, so we can determine whether 502346581Sken * or not the initiator is capable of the things that the user 502446581Sken * requests. 502546581Sken */ 502646581Sken ccb->ccb_h.func_code = XPT_PATH_INQ; 502746581Sken if (cam_send_ccb(device, ccb) < 0) { 502846581Sken perror("error sending XPT_PATH_INQ CCB"); 502974840Sken if (arglist & CAM_ARG_VERBOSE) { 503074840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 503174840Sken CAM_EPF_ALL, stderr); 503274840Sken } 503346581Sken retval = 1; 503446581Sken goto ratecontrol_bailout; 503546581Sken } 503646581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 503774840Sken warnx("XPT_PATH_INQ CCB failed"); 503874840Sken if (arglist & CAM_ARG_VERBOSE) { 503974840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 504074840Sken CAM_EPF_ALL, stderr); 504174840Sken } 504246581Sken retval = 1; 504346581Sken goto ratecontrol_bailout; 504446581Sken } 504546581Sken bcopy(&ccb->cpi, &cpi, sizeof(struct ccb_pathinq)); 504646581Sken bzero(&(&ccb->ccb_h)[1], 504746581Sken sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr)); 5048199821Smav if (quiet == 0) { 5049199821Smav fprintf(stdout, "%s parameters:\n", 5050199821Smav user_settings ? "User" : "Current"); 5051199821Smav } 505246581Sken retval = get_print_cts(device, user_settings, quiet, &ccb->cts); 505346581Sken if (retval != 0) 505446581Sken goto ratecontrol_bailout; 505546581Sken 505646581Sken if (arglist & CAM_ARG_VERBOSE) 505746581Sken cpi_print(&cpi); 505846581Sken 505946581Sken if (change_settings) { 5060163896Smjacob int didsettings = 0; 5061163896Smjacob struct ccb_trans_settings_spi *spi = NULL; 5062236437Smav struct ccb_trans_settings_pata *pata = NULL; 5063236437Smav struct ccb_trans_settings_sata *sata = NULL; 5064199821Smav struct ccb_trans_settings_ata *ata = NULL; 5065163896Smjacob struct ccb_trans_settings_scsi *scsi = NULL; 5066163896Smjacob 5067199821Smav if (ccb->cts.transport == XPORT_SPI) 5068163896Smjacob spi = &ccb->cts.xport_specific.spi; 5069199821Smav if (ccb->cts.transport == XPORT_ATA) 5070236437Smav pata = &ccb->cts.xport_specific.ata; 5071199821Smav if (ccb->cts.transport == XPORT_SATA) 5072199821Smav sata = &ccb->cts.xport_specific.sata; 5073236437Smav if (ccb->cts.protocol == PROTO_ATA) 5074236437Smav ata = &ccb->cts.proto_specific.ata; 5075199821Smav if (ccb->cts.protocol == PROTO_SCSI) 5076163896Smjacob scsi = &ccb->cts.proto_specific.scsi; 5077199821Smav ccb->cts.xport_specific.valid = 0; 5078199821Smav ccb->cts.proto_specific.valid = 0; 5079163896Smjacob if (spi && disc_enable != -1) { 5080163896Smjacob spi->valid |= CTS_SPI_VALID_DISC; 508146581Sken if (disc_enable == 0) 5082163896Smjacob spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 508346581Sken else 5084163896Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 5085236285Seadler didsettings++; 5086163896Smjacob } 5087236437Smav if (tag_enable != -1) { 508846581Sken if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0) { 508946581Sken warnx("HBA does not support tagged queueing, " 509046581Sken "so you cannot modify tag settings"); 509146581Sken retval = 1; 509246581Sken goto ratecontrol_bailout; 509346581Sken } 5094236437Smav if (ata) { 5095236437Smav ata->valid |= CTS_SCSI_VALID_TQ; 5096236437Smav if (tag_enable == 0) 5097236437Smav ata->flags &= ~CTS_ATA_FLAGS_TAG_ENB; 5098236437Smav else 5099236437Smav ata->flags |= CTS_ATA_FLAGS_TAG_ENB; 5100236437Smav didsettings++; 5101236437Smav } else if (scsi) { 5102236437Smav scsi->valid |= CTS_SCSI_VALID_TQ; 5103236437Smav if (tag_enable == 0) 5104236437Smav scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 5105236437Smav else 5106236437Smav scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 5107236437Smav didsettings++; 5108236437Smav } 5109163896Smjacob } 5110163896Smjacob if (spi && offset != -1) { 511146581Sken if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) { 5112199821Smav warnx("HBA is not capable of changing offset"); 511346581Sken retval = 1; 511446581Sken goto ratecontrol_bailout; 511546581Sken } 5116163896Smjacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 5117163896Smjacob spi->sync_offset = offset; 5118163896Smjacob didsettings++; 5119163896Smjacob } 5120163896Smjacob if (spi && syncrate != -1) { 512146581Sken int prelim_sync_period; 512246581Sken 512346581Sken if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) { 5124199821Smav warnx("HBA is not capable of changing " 5125199821Smav "transfer rates"); 512646581Sken retval = 1; 512746581Sken goto ratecontrol_bailout; 512846581Sken } 5129163896Smjacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 513046581Sken /* 513146581Sken * The sync rate the user gives us is in MHz. 513246581Sken * We need to translate it into KHz for this 513346581Sken * calculation. 513446581Sken */ 513546581Sken syncrate *= 1000; 513646581Sken /* 513746581Sken * Next, we calculate a "preliminary" sync period 513846581Sken * in tenths of a nanosecond. 513946581Sken */ 514046581Sken if (syncrate == 0) 514146581Sken prelim_sync_period = 0; 514246581Sken else 514346581Sken prelim_sync_period = 10000000 / syncrate; 5144163896Smjacob spi->sync_period = 514546581Sken scsi_calc_syncparam(prelim_sync_period); 5146163896Smjacob didsettings++; 5147163896Smjacob } 5148199821Smav if (sata && syncrate != -1) { 5149199821Smav if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) { 5150199821Smav warnx("HBA is not capable of changing " 5151199821Smav "transfer rates"); 5152199821Smav retval = 1; 5153199821Smav goto ratecontrol_bailout; 5154199821Smav } 5155236437Smav if (!user_settings) { 5156236437Smav warnx("You can modify only user rate " 5157236437Smav "settings for SATA"); 5158236437Smav retval = 1; 5159236437Smav goto ratecontrol_bailout; 5160236437Smav } 5161199821Smav sata->revision = ata_speed2revision(syncrate * 100); 5162199821Smav if (sata->revision < 0) { 5163199821Smav warnx("Invalid rate %f", syncrate); 5164199821Smav retval = 1; 5165199821Smav goto ratecontrol_bailout; 5166199821Smav } 5167199821Smav sata->valid |= CTS_SATA_VALID_REVISION; 5168199821Smav didsettings++; 5169199821Smav } 5170236437Smav if ((pata || sata) && mode != -1) { 5171199821Smav if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) { 5172199821Smav warnx("HBA is not capable of changing " 5173199821Smav "transfer rates"); 5174199821Smav retval = 1; 5175199821Smav goto ratecontrol_bailout; 5176199821Smav } 5177236437Smav if (!user_settings) { 5178236437Smav warnx("You can modify only user mode " 5179236437Smav "settings for ATA/SATA"); 5180236437Smav retval = 1; 5181236437Smav goto ratecontrol_bailout; 5182236437Smav } 5183236437Smav if (pata) { 5184236437Smav pata->mode = mode; 5185236437Smav pata->valid |= CTS_ATA_VALID_MODE; 5186199821Smav } else { 5187199821Smav sata->mode = mode; 5188199821Smav sata->valid |= CTS_SATA_VALID_MODE; 5189199821Smav } 5190199821Smav didsettings++; 5191199821Smav } 519246581Sken /* 519346581Sken * The bus_width argument goes like this: 519446581Sken * 0 == 8 bit 519546581Sken * 1 == 16 bit 519646581Sken * 2 == 32 bit 519746581Sken * Therefore, if you shift the number of bits given on the 519846581Sken * command line right by 4, you should get the correct 519946581Sken * number. 520046581Sken */ 5201163896Smjacob if (spi && bus_width != -1) { 520246581Sken /* 520346581Sken * We might as well validate things here with a 520446581Sken * decipherable error message, rather than what 520546581Sken * will probably be an indecipherable error message 520646581Sken * by the time it gets back to us. 520746581Sken */ 520846581Sken if ((bus_width == 16) 520946581Sken && ((cpi.hba_inquiry & PI_WIDE_16) == 0)) { 521046581Sken warnx("HBA does not support 16 bit bus width"); 521146581Sken retval = 1; 521246581Sken goto ratecontrol_bailout; 521346581Sken } else if ((bus_width == 32) 521446581Sken && ((cpi.hba_inquiry & PI_WIDE_32) == 0)) { 521546581Sken warnx("HBA does not support 32 bit bus width"); 521646581Sken retval = 1; 521746581Sken goto ratecontrol_bailout; 521851723Sken } else if ((bus_width != 8) 521951723Sken && (bus_width != 16) 522051723Sken && (bus_width != 32)) { 522146581Sken warnx("Invalid bus width %d", bus_width); 522246581Sken retval = 1; 522346581Sken goto ratecontrol_bailout; 522446581Sken } 5225163896Smjacob spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 5226163896Smjacob spi->bus_width = bus_width >> 4; 5227163896Smjacob didsettings++; 5228163896Smjacob } 5229163896Smjacob if (didsettings == 0) { 5230163896Smjacob goto ratecontrol_bailout; 5231163896Smjacob } 523246581Sken ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 523346581Sken if (cam_send_ccb(device, ccb) < 0) { 523446581Sken perror("error sending XPT_SET_TRAN_SETTINGS CCB"); 523574840Sken if (arglist & CAM_ARG_VERBOSE) { 523674840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 523774840Sken CAM_EPF_ALL, stderr); 523874840Sken } 523946581Sken retval = 1; 524046581Sken goto ratecontrol_bailout; 524146581Sken } 524246581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 524374840Sken warnx("XPT_SET_TRANS_SETTINGS CCB failed"); 524474840Sken if (arglist & CAM_ARG_VERBOSE) { 524574840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 524674840Sken CAM_EPF_ALL, stderr); 524774840Sken } 524846581Sken retval = 1; 524946581Sken goto ratecontrol_bailout; 525046581Sken } 525146581Sken } 525246581Sken if (send_tur) { 525346581Sken retval = testunitready(device, retry_count, timeout, 525446581Sken (arglist & CAM_ARG_VERBOSE) ? 0 : 1); 525546581Sken /* 525646581Sken * If the TUR didn't succeed, just bail. 525746581Sken */ 525846581Sken if (retval != 0) { 525946581Sken if (quiet == 0) 526046581Sken fprintf(stderr, "Test Unit Ready failed\n"); 526146581Sken goto ratecontrol_bailout; 526246581Sken } 5263236437Smav } 5264236437Smav if ((change_settings || send_tur) && !quiet && 5265236437Smav (ccb->cts.transport == XPORT_ATA || 5266236437Smav ccb->cts.transport == XPORT_SATA || send_tur)) { 5267199821Smav fprintf(stdout, "New parameters:\n"); 526846581Sken retval = get_print_cts(device, user_settings, 0, NULL); 526946581Sken } 527046581Sken 527146581Skenratecontrol_bailout: 527246581Sken cam_freeccb(ccb); 527346581Sken return(retval); 527446581Sken} 527546581Sken 527660767Skenstatic int 527760767Skenscsiformat(struct cam_device *device, int argc, char **argv, 527860767Sken char *combinedopt, int retry_count, int timeout) 527960767Sken{ 528060767Sken union ccb *ccb; 528160767Sken int c; 528260767Sken int ycount = 0, quiet = 0; 5283227961Semaste int error = 0, retval = 0; 528460767Sken int use_timeout = 10800 * 1000; 528560767Sken int immediate = 1; 528660767Sken struct format_defect_list_header fh; 528760767Sken u_int8_t *data_ptr = NULL; 528860767Sken u_int32_t dxfer_len = 0; 528960767Sken u_int8_t byte2 = 0; 529060767Sken int num_warnings = 0; 5291144134Sken int reportonly = 0; 529260767Sken 529360767Sken ccb = cam_getccb(device); 529460767Sken 529560767Sken if (ccb == NULL) { 529660767Sken warnx("scsiformat: error allocating ccb"); 529760767Sken return(1); 529860767Sken } 529960767Sken 530060767Sken bzero(&(&ccb->ccb_h)[1], 530160767Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 530260767Sken 530360767Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 530460767Sken switch(c) { 530560767Sken case 'q': 530660767Sken quiet++; 530760767Sken break; 5308144134Sken case 'r': 5309144134Sken reportonly = 1; 5310144134Sken break; 531160767Sken case 'w': 531260767Sken immediate = 0; 531360767Sken break; 531460767Sken case 'y': 531560767Sken ycount++; 531660767Sken break; 531760767Sken } 531860767Sken } 531960767Sken 5320144134Sken if (reportonly) 5321144134Sken goto doreport; 5322144134Sken 532360767Sken if (quiet == 0) { 532460767Sken fprintf(stdout, "You are about to REMOVE ALL DATA from the " 532560767Sken "following device:\n"); 532660767Sken 532760767Sken error = scsidoinquiry(device, argc, argv, combinedopt, 532860767Sken retry_count, timeout); 532960767Sken 533060767Sken if (error != 0) { 533160767Sken warnx("scsiformat: error sending inquiry"); 533260767Sken goto scsiformat_bailout; 533360767Sken } 533460767Sken } 533560767Sken 533660767Sken if (ycount == 0) { 5337227961Semaste if (!get_confirmation()) { 533860767Sken error = 1; 533960767Sken goto scsiformat_bailout; 534060767Sken } 534160767Sken } 534260767Sken 534360767Sken if (timeout != 0) 534460767Sken use_timeout = timeout; 534560767Sken 534660767Sken if (quiet == 0) { 534760767Sken fprintf(stdout, "Current format timeout is %d seconds\n", 534860767Sken use_timeout / 1000); 534960767Sken } 535060767Sken 535160767Sken /* 535260767Sken * If the user hasn't disabled questions and didn't specify a 535360767Sken * timeout on the command line, ask them if they want the current 535460767Sken * timeout. 535560767Sken */ 535660767Sken if ((ycount == 0) 535760767Sken && (timeout == 0)) { 535860767Sken char str[1024]; 535960767Sken int new_timeout = 0; 536060767Sken 536160767Sken fprintf(stdout, "Enter new timeout in seconds or press\n" 536260767Sken "return to keep the current timeout [%d] ", 536360767Sken use_timeout / 1000); 536460767Sken 536560767Sken if (fgets(str, sizeof(str), stdin) != NULL) { 536660767Sken if (str[0] != '\0') 536760767Sken new_timeout = atoi(str); 536860767Sken } 536960767Sken 537060767Sken if (new_timeout != 0) { 537160767Sken use_timeout = new_timeout * 1000; 537260767Sken fprintf(stdout, "Using new timeout value %d\n", 537360767Sken use_timeout / 1000); 537460767Sken } 537560767Sken } 537660767Sken 537760767Sken /* 537860767Sken * Keep this outside the if block below to silence any unused 537960767Sken * variable warnings. 538060767Sken */ 538160767Sken bzero(&fh, sizeof(fh)); 538260767Sken 538360767Sken /* 538460767Sken * If we're in immediate mode, we've got to include the format 538560767Sken * header 538660767Sken */ 538760767Sken if (immediate != 0) { 538860767Sken fh.byte2 = FU_DLH_IMMED; 538960767Sken data_ptr = (u_int8_t *)&fh; 539060767Sken dxfer_len = sizeof(fh); 539160767Sken byte2 = FU_FMT_DATA; 539260767Sken } else if (quiet == 0) { 539360767Sken fprintf(stdout, "Formatting..."); 539460767Sken fflush(stdout); 539560767Sken } 539660767Sken 539760767Sken scsi_format_unit(&ccb->csio, 539860767Sken /* retries */ retry_count, 539960767Sken /* cbfcnp */ NULL, 540060767Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 540160767Sken /* byte2 */ byte2, 540260767Sken /* ileave */ 0, 540360767Sken /* data_ptr */ data_ptr, 540460767Sken /* dxfer_len */ dxfer_len, 540560767Sken /* sense_len */ SSD_FULL_SIZE, 540660767Sken /* timeout */ use_timeout); 540760767Sken 540860767Sken /* Disable freezing the device queue */ 540960767Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 541060767Sken 541160767Sken if (arglist & CAM_ARG_ERR_RECOVER) 541260767Sken ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 541360767Sken 541460767Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 541560767Sken || ((immediate == 0) 541660767Sken && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP))) { 541769254Skris const char errstr[] = "error sending format command"; 541860767Sken 541960767Sken if (retval < 0) 542060767Sken warn(errstr); 542160767Sken else 542260767Sken warnx(errstr); 542360767Sken 542460767Sken if (arglist & CAM_ARG_VERBOSE) { 542574840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 542674840Sken CAM_EPF_ALL, stderr); 542760767Sken } 542860767Sken error = 1; 542960767Sken goto scsiformat_bailout; 543060767Sken } 543160767Sken 543260767Sken /* 543360767Sken * If we ran in non-immediate mode, we already checked for errors 543460767Sken * above and printed out any necessary information. If we're in 543560767Sken * immediate mode, we need to loop through and get status 543660767Sken * information periodically. 543760767Sken */ 543860767Sken if (immediate == 0) { 543960767Sken if (quiet == 0) { 544060767Sken fprintf(stdout, "Format Complete\n"); 544160767Sken } 544260767Sken goto scsiformat_bailout; 544360767Sken } 544460767Sken 5445144134Skendoreport: 544660767Sken do { 544760767Sken cam_status status; 544860767Sken 544960767Sken bzero(&(&ccb->ccb_h)[1], 545060767Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 545160767Sken 545260767Sken /* 545360767Sken * There's really no need to do error recovery or 545460767Sken * retries here, since we're just going to sit in a 545560767Sken * loop and wait for the device to finish formatting. 545660767Sken */ 545760767Sken scsi_test_unit_ready(&ccb->csio, 545860767Sken /* retries */ 0, 545960767Sken /* cbfcnp */ NULL, 546060767Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 546160767Sken /* sense_len */ SSD_FULL_SIZE, 546260767Sken /* timeout */ 5000); 546360767Sken 546460767Sken /* Disable freezing the device queue */ 546560767Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 546660767Sken 546760767Sken retval = cam_send_ccb(device, ccb); 546860767Sken 546960767Sken /* 547060767Sken * If we get an error from the ioctl, bail out. SCSI 547160767Sken * errors are expected. 547260767Sken */ 547360767Sken if (retval < 0) { 547460767Sken warn("error sending CAMIOCOMMAND ioctl"); 547560767Sken if (arglist & CAM_ARG_VERBOSE) { 547674840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 547774840Sken CAM_EPF_ALL, stderr); 547860767Sken } 547960767Sken error = 1; 548060767Sken goto scsiformat_bailout; 548160767Sken } 548260767Sken 548360767Sken status = ccb->ccb_h.status & CAM_STATUS_MASK; 548460767Sken 548560767Sken if ((status != CAM_REQ_CMP) 548674840Sken && (status == CAM_SCSI_STATUS_ERROR) 5487144134Sken && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) { 548860767Sken struct scsi_sense_data *sense; 548960767Sken int error_code, sense_key, asc, ascq; 549060767Sken 549160767Sken sense = &ccb->csio.sense_data; 5492225950Sken scsi_extract_sense_len(sense, ccb->csio.sense_len - 5493225950Sken ccb->csio.sense_resid, &error_code, &sense_key, 5494225950Sken &asc, &ascq, /*show_errors*/ 1); 549560767Sken 549660767Sken /* 549760767Sken * According to the SCSI-2 and SCSI-3 specs, a 549860767Sken * drive that is in the middle of a format should 549960767Sken * return NOT READY with an ASC of "logical unit 550060767Sken * not ready, format in progress". The sense key 550160767Sken * specific bytes will then be a progress indicator. 550260767Sken */ 550360767Sken if ((sense_key == SSD_KEY_NOT_READY) 550460767Sken && (asc == 0x04) && (ascq == 0x04)) { 5505225950Sken uint8_t sks[3]; 5506225950Sken 5507225950Sken if ((scsi_get_sks(sense, ccb->csio.sense_len - 5508225950Sken ccb->csio.sense_resid, sks) == 0) 550960767Sken && (quiet == 0)) { 551060767Sken int val; 551160767Sken u_int64_t percentage; 551260767Sken 5513225950Sken val = scsi_2btoul(&sks[1]); 551460767Sken percentage = 10000 * val; 551560767Sken 551660767Sken fprintf(stdout, 5517111195Sjohan "\rFormatting: %ju.%02u %% " 551860767Sken "(%d/%d) done", 5519214321Smav (uintmax_t)(percentage / 5520111195Sjohan (0x10000 * 100)), 5521214321Smav (unsigned)((percentage / 5522111195Sjohan 0x10000) % 100), 552360767Sken val, 0x10000); 552460767Sken fflush(stdout); 552560767Sken } else if ((quiet == 0) 552660767Sken && (++num_warnings <= 1)) { 552760767Sken warnx("Unexpected SCSI Sense Key " 552860767Sken "Specific value returned " 552960767Sken "during format:"); 553060767Sken scsi_sense_print(device, &ccb->csio, 553160767Sken stderr); 553260767Sken warnx("Unable to print status " 553360767Sken "information, but format will " 553460767Sken "proceed."); 553560767Sken warnx("will exit when format is " 553660767Sken "complete"); 553760767Sken } 553860767Sken sleep(1); 553960767Sken } else { 554060767Sken warnx("Unexpected SCSI error during format"); 554174840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 554274840Sken CAM_EPF_ALL, stderr); 554360767Sken error = 1; 554460767Sken goto scsiformat_bailout; 554560767Sken } 554660767Sken 554760767Sken } else if (status != CAM_REQ_CMP) { 554860767Sken warnx("Unexpected CAM status %#x", status); 554974840Sken if (arglist & CAM_ARG_VERBOSE) 555074840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 555174840Sken CAM_EPF_ALL, stderr); 555260767Sken error = 1; 555360767Sken goto scsiformat_bailout; 555460767Sken } 555560767Sken 555660767Sken } while((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP); 555760767Sken 555860767Sken if (quiet == 0) 555960767Sken fprintf(stdout, "\nFormat Complete\n"); 556060767Sken 556160767Skenscsiformat_bailout: 556260767Sken 556360767Sken cam_freeccb(ccb); 556460767Sken 556560767Sken return(error); 556660767Sken} 5567161506Sken 5568161506Skenstatic int 5569255307Sbryanvscsisanitize(struct cam_device *device, int argc, char **argv, 5570255307Sbryanv char *combinedopt, int retry_count, int timeout) 5571255307Sbryanv{ 5572255307Sbryanv union ccb *ccb; 5573255307Sbryanv u_int8_t action = 0; 5574255307Sbryanv int c; 5575255307Sbryanv int ycount = 0, quiet = 0; 5576255307Sbryanv int error = 0, retval = 0; 5577255307Sbryanv int use_timeout = 10800 * 1000; 5578255307Sbryanv int immediate = 1; 5579255307Sbryanv int invert = 0; 5580255307Sbryanv int passes = 0; 5581255307Sbryanv int ause = 0; 5582255307Sbryanv int fd = -1; 5583255307Sbryanv const char *pattern = NULL; 5584255307Sbryanv u_int8_t *data_ptr = NULL; 5585255307Sbryanv u_int32_t dxfer_len = 0; 5586255307Sbryanv u_int8_t byte2 = 0; 5587255307Sbryanv int num_warnings = 0; 5588255307Sbryanv int reportonly = 0; 5589255307Sbryanv 5590255307Sbryanv ccb = cam_getccb(device); 5591255307Sbryanv 5592255307Sbryanv if (ccb == NULL) { 5593255307Sbryanv warnx("scsisanitize: error allocating ccb"); 5594255307Sbryanv return(1); 5595255307Sbryanv } 5596255307Sbryanv 5597255307Sbryanv bzero(&(&ccb->ccb_h)[1], 5598255307Sbryanv sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 5599255307Sbryanv 5600255307Sbryanv while ((c = getopt(argc, argv, combinedopt)) != -1) { 5601255307Sbryanv switch(c) { 5602255307Sbryanv case 'a': 5603255307Sbryanv if (strcasecmp(optarg, "overwrite") == 0) 5604255307Sbryanv action = SSZ_SERVICE_ACTION_OVERWRITE; 5605255307Sbryanv else if (strcasecmp(optarg, "block") == 0) 5606255307Sbryanv action = SSZ_SERVICE_ACTION_BLOCK_ERASE; 5607255307Sbryanv else if (strcasecmp(optarg, "crypto") == 0) 5608255307Sbryanv action = SSZ_SERVICE_ACTION_CRYPTO_ERASE; 5609255307Sbryanv else if (strcasecmp(optarg, "exitfailure") == 0) 5610255307Sbryanv action = SSZ_SERVICE_ACTION_EXIT_MODE_FAILURE; 5611255307Sbryanv else { 5612255307Sbryanv warnx("invalid service operation \"%s\"", 5613255307Sbryanv optarg); 5614255307Sbryanv error = 1; 5615255307Sbryanv goto scsisanitize_bailout; 5616255307Sbryanv } 5617255307Sbryanv break; 5618255307Sbryanv case 'c': 5619255307Sbryanv passes = strtol(optarg, NULL, 0); 5620255307Sbryanv if (passes < 1 || passes > 31) { 5621255307Sbryanv warnx("invalid passes value %d", passes); 5622255307Sbryanv error = 1; 5623255307Sbryanv goto scsisanitize_bailout; 5624255307Sbryanv } 5625255307Sbryanv break; 5626255307Sbryanv case 'I': 5627255307Sbryanv invert = 1; 5628255307Sbryanv break; 5629255307Sbryanv case 'P': 5630255307Sbryanv pattern = optarg; 5631255307Sbryanv break; 5632255307Sbryanv case 'q': 5633255307Sbryanv quiet++; 5634255307Sbryanv break; 5635255307Sbryanv case 'U': 5636255307Sbryanv ause = 1; 5637255307Sbryanv break; 5638255307Sbryanv case 'r': 5639255307Sbryanv reportonly = 1; 5640255307Sbryanv break; 5641255307Sbryanv case 'w': 5642255307Sbryanv immediate = 0; 5643255307Sbryanv break; 5644255307Sbryanv case 'y': 5645255307Sbryanv ycount++; 5646255307Sbryanv break; 5647255307Sbryanv } 5648255307Sbryanv } 5649255307Sbryanv 5650255307Sbryanv if (reportonly) 5651255307Sbryanv goto doreport; 5652255307Sbryanv 5653255307Sbryanv if (action == 0) { 5654255307Sbryanv warnx("an action is required"); 5655255307Sbryanv error = 1; 5656255307Sbryanv goto scsisanitize_bailout; 5657255307Sbryanv } else if (action == SSZ_SERVICE_ACTION_OVERWRITE) { 5658255307Sbryanv struct scsi_sanitize_parameter_list *pl; 5659255307Sbryanv struct stat sb; 5660255307Sbryanv ssize_t sz, amt; 5661255307Sbryanv 5662255307Sbryanv if (pattern == NULL) { 5663255307Sbryanv warnx("overwrite action requires -P argument"); 5664255307Sbryanv error = 1; 5665255307Sbryanv goto scsisanitize_bailout; 5666255307Sbryanv } 5667255307Sbryanv fd = open(pattern, O_RDONLY); 5668255307Sbryanv if (fd < 0) { 5669255307Sbryanv warn("cannot open pattern file %s", pattern); 5670255307Sbryanv error = 1; 5671255307Sbryanv goto scsisanitize_bailout; 5672255307Sbryanv } 5673255307Sbryanv if (fstat(fd, &sb) < 0) { 5674255307Sbryanv warn("cannot stat pattern file %s", pattern); 5675255307Sbryanv error = 1; 5676255307Sbryanv goto scsisanitize_bailout; 5677255307Sbryanv } 5678255307Sbryanv sz = sb.st_size; 5679255307Sbryanv if (sz > SSZPL_MAX_PATTERN_LENGTH) { 5680255307Sbryanv warnx("pattern file size exceeds maximum value %d", 5681255307Sbryanv SSZPL_MAX_PATTERN_LENGTH); 5682255307Sbryanv error = 1; 5683255307Sbryanv goto scsisanitize_bailout; 5684255307Sbryanv } 5685255307Sbryanv dxfer_len = sizeof(*pl) + sz; 5686255307Sbryanv data_ptr = calloc(1, dxfer_len); 5687255307Sbryanv if (data_ptr == NULL) { 5688255307Sbryanv warnx("cannot allocate parameter list buffer"); 5689255307Sbryanv error = 1; 5690255307Sbryanv goto scsisanitize_bailout; 5691255307Sbryanv } 5692255307Sbryanv 5693255307Sbryanv amt = read(fd, data_ptr + sizeof(*pl), sz); 5694255307Sbryanv if (amt < 0) { 5695255307Sbryanv warn("cannot read pattern file"); 5696255307Sbryanv error = 1; 5697255307Sbryanv goto scsisanitize_bailout; 5698255307Sbryanv } else if (amt != sz) { 5699255307Sbryanv warnx("short pattern file read"); 5700255307Sbryanv error = 1; 5701255307Sbryanv goto scsisanitize_bailout; 5702255307Sbryanv } 5703255307Sbryanv 5704255307Sbryanv pl = (struct scsi_sanitize_parameter_list *)data_ptr; 5705255307Sbryanv if (passes == 0) 5706255307Sbryanv pl->byte1 = 1; 5707255307Sbryanv else 5708255307Sbryanv pl->byte1 = passes; 5709255307Sbryanv if (invert != 0) 5710255307Sbryanv pl->byte1 |= SSZPL_INVERT; 5711255307Sbryanv scsi_ulto2b(sz, pl->length); 5712255307Sbryanv } else { 5713255307Sbryanv const char *arg; 5714255307Sbryanv 5715255307Sbryanv if (passes != 0) 5716255307Sbryanv arg = "-c"; 5717255307Sbryanv else if (invert != 0) 5718255307Sbryanv arg = "-I"; 5719255307Sbryanv else if (pattern != NULL) 5720255307Sbryanv arg = "-P"; 5721255307Sbryanv else 5722255307Sbryanv arg = NULL; 5723255307Sbryanv if (arg != NULL) { 5724255307Sbryanv warnx("%s argument only valid with overwrite " 5725255307Sbryanv "operation", arg); 5726255307Sbryanv error = 1; 5727255307Sbryanv goto scsisanitize_bailout; 5728255307Sbryanv } 5729255307Sbryanv } 5730255307Sbryanv 5731255307Sbryanv if (quiet == 0) { 5732255307Sbryanv fprintf(stdout, "You are about to REMOVE ALL DATA from the " 5733255307Sbryanv "following device:\n"); 5734255307Sbryanv 5735255307Sbryanv error = scsidoinquiry(device, argc, argv, combinedopt, 5736255307Sbryanv retry_count, timeout); 5737255307Sbryanv 5738255307Sbryanv if (error != 0) { 5739255307Sbryanv warnx("scsisanitize: error sending inquiry"); 5740255307Sbryanv goto scsisanitize_bailout; 5741255307Sbryanv } 5742255307Sbryanv } 5743255307Sbryanv 5744255307Sbryanv if (ycount == 0) { 5745255307Sbryanv if (!get_confirmation()) { 5746255307Sbryanv error = 1; 5747255307Sbryanv goto scsisanitize_bailout; 5748255307Sbryanv } 5749255307Sbryanv } 5750255307Sbryanv 5751255307Sbryanv if (timeout != 0) 5752255307Sbryanv use_timeout = timeout; 5753255307Sbryanv 5754255307Sbryanv if (quiet == 0) { 5755255307Sbryanv fprintf(stdout, "Current sanitize timeout is %d seconds\n", 5756255307Sbryanv use_timeout / 1000); 5757255307Sbryanv } 5758255307Sbryanv 5759255307Sbryanv /* 5760255307Sbryanv * If the user hasn't disabled questions and didn't specify a 5761255307Sbryanv * timeout on the command line, ask them if they want the current 5762255307Sbryanv * timeout. 5763255307Sbryanv */ 5764255307Sbryanv if ((ycount == 0) 5765255307Sbryanv && (timeout == 0)) { 5766255307Sbryanv char str[1024]; 5767255307Sbryanv int new_timeout = 0; 5768255307Sbryanv 5769255307Sbryanv fprintf(stdout, "Enter new timeout in seconds or press\n" 5770255307Sbryanv "return to keep the current timeout [%d] ", 5771255307Sbryanv use_timeout / 1000); 5772255307Sbryanv 5773255307Sbryanv if (fgets(str, sizeof(str), stdin) != NULL) { 5774255307Sbryanv if (str[0] != '\0') 5775255307Sbryanv new_timeout = atoi(str); 5776255307Sbryanv } 5777255307Sbryanv 5778255307Sbryanv if (new_timeout != 0) { 5779255307Sbryanv use_timeout = new_timeout * 1000; 5780255307Sbryanv fprintf(stdout, "Using new timeout value %d\n", 5781255307Sbryanv use_timeout / 1000); 5782255307Sbryanv } 5783255307Sbryanv } 5784255307Sbryanv 5785255307Sbryanv byte2 = action; 5786255307Sbryanv if (ause != 0) 5787255307Sbryanv byte2 |= SSZ_UNRESTRICTED_EXIT; 5788255307Sbryanv if (immediate != 0) 5789255307Sbryanv byte2 |= SSZ_IMMED; 5790255307Sbryanv 5791255307Sbryanv scsi_sanitize(&ccb->csio, 5792255307Sbryanv /* retries */ retry_count, 5793255307Sbryanv /* cbfcnp */ NULL, 5794255307Sbryanv /* tag_action */ MSG_SIMPLE_Q_TAG, 5795255307Sbryanv /* byte2 */ byte2, 5796255307Sbryanv /* control */ 0, 5797255307Sbryanv /* data_ptr */ data_ptr, 5798255307Sbryanv /* dxfer_len */ dxfer_len, 5799255307Sbryanv /* sense_len */ SSD_FULL_SIZE, 5800255307Sbryanv /* timeout */ use_timeout); 5801255307Sbryanv 5802255307Sbryanv /* Disable freezing the device queue */ 5803255307Sbryanv ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 5804255307Sbryanv 5805255307Sbryanv if (arglist & CAM_ARG_ERR_RECOVER) 5806255307Sbryanv ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 5807255307Sbryanv 5808255307Sbryanv if (((retval = cam_send_ccb(device, ccb)) < 0) 5809255307Sbryanv || ((immediate == 0) 5810255307Sbryanv && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP))) { 5811255307Sbryanv const char errstr[] = "error sending sanitize command"; 5812255307Sbryanv 5813255307Sbryanv if (retval < 0) 5814255307Sbryanv warn(errstr); 5815255307Sbryanv else 5816255307Sbryanv warnx(errstr); 5817255307Sbryanv 5818255307Sbryanv if (arglist & CAM_ARG_VERBOSE) { 5819255307Sbryanv cam_error_print(device, ccb, CAM_ESF_ALL, 5820255307Sbryanv CAM_EPF_ALL, stderr); 5821255307Sbryanv } 5822255307Sbryanv error = 1; 5823255307Sbryanv goto scsisanitize_bailout; 5824255307Sbryanv } 5825255307Sbryanv 5826255307Sbryanv /* 5827255307Sbryanv * If we ran in non-immediate mode, we already checked for errors 5828255307Sbryanv * above and printed out any necessary information. If we're in 5829255307Sbryanv * immediate mode, we need to loop through and get status 5830255307Sbryanv * information periodically. 5831255307Sbryanv */ 5832255307Sbryanv if (immediate == 0) { 5833255307Sbryanv if (quiet == 0) { 5834255307Sbryanv fprintf(stdout, "Sanitize Complete\n"); 5835255307Sbryanv } 5836255307Sbryanv goto scsisanitize_bailout; 5837255307Sbryanv } 5838255307Sbryanv 5839255307Sbryanvdoreport: 5840255307Sbryanv do { 5841255307Sbryanv cam_status status; 5842255307Sbryanv 5843255307Sbryanv bzero(&(&ccb->ccb_h)[1], 5844255307Sbryanv sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 5845255307Sbryanv 5846255307Sbryanv /* 5847255307Sbryanv * There's really no need to do error recovery or 5848255307Sbryanv * retries here, since we're just going to sit in a 5849255307Sbryanv * loop and wait for the device to finish sanitizing. 5850255307Sbryanv */ 5851255307Sbryanv scsi_test_unit_ready(&ccb->csio, 5852255307Sbryanv /* retries */ 0, 5853255307Sbryanv /* cbfcnp */ NULL, 5854255307Sbryanv /* tag_action */ MSG_SIMPLE_Q_TAG, 5855255307Sbryanv /* sense_len */ SSD_FULL_SIZE, 5856255307Sbryanv /* timeout */ 5000); 5857255307Sbryanv 5858255307Sbryanv /* Disable freezing the device queue */ 5859255307Sbryanv ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 5860255307Sbryanv 5861255307Sbryanv retval = cam_send_ccb(device, ccb); 5862255307Sbryanv 5863255307Sbryanv /* 5864255307Sbryanv * If we get an error from the ioctl, bail out. SCSI 5865255307Sbryanv * errors are expected. 5866255307Sbryanv */ 5867255307Sbryanv if (retval < 0) { 5868255307Sbryanv warn("error sending CAMIOCOMMAND ioctl"); 5869255307Sbryanv if (arglist & CAM_ARG_VERBOSE) { 5870255307Sbryanv cam_error_print(device, ccb, CAM_ESF_ALL, 5871255307Sbryanv CAM_EPF_ALL, stderr); 5872255307Sbryanv } 5873255307Sbryanv error = 1; 5874255307Sbryanv goto scsisanitize_bailout; 5875255307Sbryanv } 5876255307Sbryanv 5877255307Sbryanv status = ccb->ccb_h.status & CAM_STATUS_MASK; 5878255307Sbryanv 5879255307Sbryanv if ((status != CAM_REQ_CMP) 5880255307Sbryanv && (status == CAM_SCSI_STATUS_ERROR) 5881255307Sbryanv && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) { 5882255307Sbryanv struct scsi_sense_data *sense; 5883255307Sbryanv int error_code, sense_key, asc, ascq; 5884255307Sbryanv 5885255307Sbryanv sense = &ccb->csio.sense_data; 5886255307Sbryanv scsi_extract_sense_len(sense, ccb->csio.sense_len - 5887255307Sbryanv ccb->csio.sense_resid, &error_code, &sense_key, 5888255307Sbryanv &asc, &ascq, /*show_errors*/ 1); 5889255307Sbryanv 5890255307Sbryanv /* 5891255307Sbryanv * According to the SCSI-3 spec, a drive that is in the 5892255307Sbryanv * middle of a sanitize should return NOT READY with an 5893255307Sbryanv * ASC of "logical unit not ready, sanitize in 5894255307Sbryanv * progress". The sense key specific bytes will then 5895255307Sbryanv * be a progress indicator. 5896255307Sbryanv */ 5897255307Sbryanv if ((sense_key == SSD_KEY_NOT_READY) 5898255307Sbryanv && (asc == 0x04) && (ascq == 0x1b)) { 5899255307Sbryanv uint8_t sks[3]; 5900255307Sbryanv 5901255307Sbryanv if ((scsi_get_sks(sense, ccb->csio.sense_len - 5902255307Sbryanv ccb->csio.sense_resid, sks) == 0) 5903255307Sbryanv && (quiet == 0)) { 5904255307Sbryanv int val; 5905255307Sbryanv u_int64_t percentage; 5906255307Sbryanv 5907255307Sbryanv val = scsi_2btoul(&sks[1]); 5908255307Sbryanv percentage = 10000 * val; 5909255307Sbryanv 5910255307Sbryanv fprintf(stdout, 5911255307Sbryanv "\rSanitizing: %ju.%02u %% " 5912255307Sbryanv "(%d/%d) done", 5913255307Sbryanv (uintmax_t)(percentage / 5914255307Sbryanv (0x10000 * 100)), 5915255307Sbryanv (unsigned)((percentage / 5916255307Sbryanv 0x10000) % 100), 5917255307Sbryanv val, 0x10000); 5918255307Sbryanv fflush(stdout); 5919255307Sbryanv } else if ((quiet == 0) 5920255307Sbryanv && (++num_warnings <= 1)) { 5921255307Sbryanv warnx("Unexpected SCSI Sense Key " 5922255307Sbryanv "Specific value returned " 5923255307Sbryanv "during sanitize:"); 5924255307Sbryanv scsi_sense_print(device, &ccb->csio, 5925255307Sbryanv stderr); 5926255307Sbryanv warnx("Unable to print status " 5927255307Sbryanv "information, but sanitze will " 5928255307Sbryanv "proceed."); 5929255307Sbryanv warnx("will exit when sanitize is " 5930255307Sbryanv "complete"); 5931255307Sbryanv } 5932255307Sbryanv sleep(1); 5933255307Sbryanv } else { 5934255307Sbryanv warnx("Unexpected SCSI error during sanitize"); 5935255307Sbryanv cam_error_print(device, ccb, CAM_ESF_ALL, 5936255307Sbryanv CAM_EPF_ALL, stderr); 5937255307Sbryanv error = 1; 5938255307Sbryanv goto scsisanitize_bailout; 5939255307Sbryanv } 5940255307Sbryanv 5941255307Sbryanv } else if (status != CAM_REQ_CMP) { 5942255307Sbryanv warnx("Unexpected CAM status %#x", status); 5943255307Sbryanv if (arglist & CAM_ARG_VERBOSE) 5944255307Sbryanv cam_error_print(device, ccb, CAM_ESF_ALL, 5945255307Sbryanv CAM_EPF_ALL, stderr); 5946255307Sbryanv error = 1; 5947255307Sbryanv goto scsisanitize_bailout; 5948255307Sbryanv } 5949255307Sbryanv } while((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP); 5950255307Sbryanv 5951255307Sbryanv if (quiet == 0) 5952255307Sbryanv fprintf(stdout, "\nSanitize Complete\n"); 5953255307Sbryanv 5954255307Sbryanvscsisanitize_bailout: 5955255307Sbryanv if (fd >= 0) 5956255307Sbryanv close(fd); 5957255307Sbryanv if (data_ptr != NULL) 5958255307Sbryanv free(data_ptr); 5959255307Sbryanv cam_freeccb(ccb); 5960255307Sbryanv 5961255307Sbryanv return(error); 5962255307Sbryanv} 5963255307Sbryanv 5964255307Sbryanvstatic int 5965161506Skenscsireportluns(struct cam_device *device, int argc, char **argv, 5966161506Sken char *combinedopt, int retry_count, int timeout) 5967161506Sken{ 5968161506Sken union ccb *ccb; 5969161506Sken int c, countonly, lunsonly; 5970161506Sken struct scsi_report_luns_data *lundata; 5971161506Sken int alloc_len; 5972161506Sken uint8_t report_type; 5973161506Sken uint32_t list_len, i, j; 5974161506Sken int retval; 5975161506Sken 5976161506Sken retval = 0; 5977161506Sken lundata = NULL; 5978161506Sken report_type = RPL_REPORT_DEFAULT; 5979161506Sken ccb = cam_getccb(device); 5980161506Sken 5981161506Sken if (ccb == NULL) { 5982161506Sken warnx("%s: error allocating ccb", __func__); 5983161506Sken return (1); 5984161506Sken } 5985161506Sken 5986161506Sken bzero(&(&ccb->ccb_h)[1], 5987161506Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 5988161506Sken 5989161506Sken countonly = 0; 5990161506Sken lunsonly = 0; 5991161506Sken 5992161506Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 5993161506Sken switch (c) { 5994161506Sken case 'c': 5995161506Sken countonly++; 5996161506Sken break; 5997161506Sken case 'l': 5998161506Sken lunsonly++; 5999161506Sken break; 6000161506Sken case 'r': 6001161506Sken if (strcasecmp(optarg, "default") == 0) 6002161506Sken report_type = RPL_REPORT_DEFAULT; 6003161506Sken else if (strcasecmp(optarg, "wellknown") == 0) 6004161506Sken report_type = RPL_REPORT_WELLKNOWN; 6005161506Sken else if (strcasecmp(optarg, "all") == 0) 6006161506Sken report_type = RPL_REPORT_ALL; 6007161506Sken else { 6008161506Sken warnx("%s: invalid report type \"%s\"", 6009161506Sken __func__, optarg); 6010161506Sken retval = 1; 6011161506Sken goto bailout; 6012161506Sken } 6013161506Sken break; 6014161506Sken default: 6015161506Sken break; 6016161506Sken } 6017161506Sken } 6018161506Sken 6019161506Sken if ((countonly != 0) 6020161506Sken && (lunsonly != 0)) { 6021161506Sken warnx("%s: you can only specify one of -c or -l", __func__); 6022161506Sken retval = 1; 6023161506Sken goto bailout; 6024161506Sken } 6025161506Sken /* 6026161506Sken * According to SPC-4, the allocation length must be at least 16 6027161506Sken * bytes -- enough for the header and one LUN. 6028161506Sken */ 6029161506Sken alloc_len = sizeof(*lundata) + 8; 6030161506Sken 6031161506Skenretry: 6032161506Sken 6033161506Sken lundata = malloc(alloc_len); 6034161506Sken 6035161506Sken if (lundata == NULL) { 6036161506Sken warn("%s: error mallocing %d bytes", __func__, alloc_len); 6037161506Sken retval = 1; 6038161506Sken goto bailout; 6039161506Sken } 6040161506Sken 6041161506Sken scsi_report_luns(&ccb->csio, 6042161506Sken /*retries*/ retry_count, 6043161506Sken /*cbfcnp*/ NULL, 6044161506Sken /*tag_action*/ MSG_SIMPLE_Q_TAG, 6045161506Sken /*select_report*/ report_type, 6046161506Sken /*rpl_buf*/ lundata, 6047161506Sken /*alloc_len*/ alloc_len, 6048161506Sken /*sense_len*/ SSD_FULL_SIZE, 6049161506Sken /*timeout*/ timeout ? timeout : 5000); 6050161506Sken 6051161506Sken /* Disable freezing the device queue */ 6052161506Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 6053161506Sken 6054161506Sken if (arglist & CAM_ARG_ERR_RECOVER) 6055161506Sken ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 6056161506Sken 6057161506Sken if (cam_send_ccb(device, ccb) < 0) { 6058161506Sken warn("error sending REPORT LUNS command"); 6059161506Sken 6060161506Sken if (arglist & CAM_ARG_VERBOSE) 6061161506Sken cam_error_print(device, ccb, CAM_ESF_ALL, 6062161506Sken CAM_EPF_ALL, stderr); 6063161506Sken 6064161506Sken retval = 1; 6065161506Sken goto bailout; 6066161506Sken } 6067161506Sken 6068161506Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 6069161506Sken cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); 6070161506Sken retval = 1; 6071161506Sken goto bailout; 6072161506Sken } 6073161506Sken 6074161506Sken 6075161506Sken list_len = scsi_4btoul(lundata->length); 6076161506Sken 6077161506Sken /* 6078161506Sken * If we need to list the LUNs, and our allocation 6079161506Sken * length was too short, reallocate and retry. 6080161506Sken */ 6081161506Sken if ((countonly == 0) 6082161506Sken && (list_len > (alloc_len - sizeof(*lundata)))) { 6083161506Sken alloc_len = list_len + sizeof(*lundata); 6084161506Sken free(lundata); 6085161506Sken goto retry; 6086161506Sken } 6087161506Sken 6088161506Sken if (lunsonly == 0) 6089161506Sken fprintf(stdout, "%u LUN%s found\n", list_len / 8, 6090161506Sken ((list_len / 8) > 1) ? "s" : ""); 6091161506Sken 6092161506Sken if (countonly != 0) 6093161506Sken goto bailout; 6094161506Sken 6095161506Sken for (i = 0; i < (list_len / 8); i++) { 6096161506Sken int no_more; 6097161506Sken 6098161506Sken no_more = 0; 6099161506Sken for (j = 0; j < sizeof(lundata->luns[i].lundata); j += 2) { 6100161506Sken if (j != 0) 6101161506Sken fprintf(stdout, ","); 6102161506Sken switch (lundata->luns[i].lundata[j] & 6103161506Sken RPL_LUNDATA_ATYP_MASK) { 6104161506Sken case RPL_LUNDATA_ATYP_PERIPH: 6105161506Sken if ((lundata->luns[i].lundata[j] & 6106161506Sken RPL_LUNDATA_PERIPH_BUS_MASK) != 0) 6107214321Smav fprintf(stdout, "%d:", 6108161506Sken lundata->luns[i].lundata[j] & 6109161506Sken RPL_LUNDATA_PERIPH_BUS_MASK); 6110161506Sken else if ((j == 0) 6111161506Sken && ((lundata->luns[i].lundata[j+2] & 6112161506Sken RPL_LUNDATA_PERIPH_BUS_MASK) == 0)) 6113161506Sken no_more = 1; 6114161506Sken 6115161506Sken fprintf(stdout, "%d", 6116161506Sken lundata->luns[i].lundata[j+1]); 6117161506Sken break; 6118161506Sken case RPL_LUNDATA_ATYP_FLAT: { 6119161506Sken uint8_t tmplun[2]; 6120161506Sken tmplun[0] = lundata->luns[i].lundata[j] & 6121161506Sken RPL_LUNDATA_FLAT_LUN_MASK; 6122161506Sken tmplun[1] = lundata->luns[i].lundata[j+1]; 6123161506Sken 6124161506Sken fprintf(stdout, "%d", scsi_2btoul(tmplun)); 6125161506Sken no_more = 1; 6126161506Sken break; 6127161506Sken } 6128161506Sken case RPL_LUNDATA_ATYP_LUN: 6129161506Sken fprintf(stdout, "%d:%d:%d", 6130161506Sken (lundata->luns[i].lundata[j+1] & 6131161506Sken RPL_LUNDATA_LUN_BUS_MASK) >> 5, 6132161506Sken lundata->luns[i].lundata[j] & 6133161506Sken RPL_LUNDATA_LUN_TARG_MASK, 6134161506Sken lundata->luns[i].lundata[j+1] & 6135161506Sken RPL_LUNDATA_LUN_LUN_MASK); 6136161506Sken break; 6137161506Sken case RPL_LUNDATA_ATYP_EXTLUN: { 6138229919Seadler int field_len_code, eam_code; 6139161506Sken 6140161506Sken eam_code = lundata->luns[i].lundata[j] & 6141161506Sken RPL_LUNDATA_EXT_EAM_MASK; 6142161506Sken field_len_code = (lundata->luns[i].lundata[j] & 6143161506Sken RPL_LUNDATA_EXT_LEN_MASK) >> 4; 6144214321Smav 6145161506Sken if ((eam_code == RPL_LUNDATA_EXT_EAM_WK) 6146161506Sken && (field_len_code == 0x00)) { 6147161506Sken fprintf(stdout, "%d", 6148161506Sken lundata->luns[i].lundata[j+1]); 6149161506Sken } else if ((eam_code == 6150161506Sken RPL_LUNDATA_EXT_EAM_NOT_SPEC) 6151161506Sken && (field_len_code == 0x03)) { 6152161506Sken uint8_t tmp_lun[8]; 6153161506Sken 6154161506Sken /* 6155161506Sken * This format takes up all 8 bytes. 6156161506Sken * If we aren't starting at offset 0, 6157161506Sken * that's a bug. 6158161506Sken */ 6159161506Sken if (j != 0) { 6160161506Sken fprintf(stdout, "Invalid " 6161161506Sken "offset %d for " 6162161506Sken "Extended LUN not " 6163161506Sken "specified format", j); 6164161506Sken no_more = 1; 6165161506Sken break; 6166161506Sken } 6167161506Sken bzero(tmp_lun, sizeof(tmp_lun)); 6168161506Sken bcopy(&lundata->luns[i].lundata[j+1], 6169161506Sken &tmp_lun[1], sizeof(tmp_lun) - 1); 6170161506Sken fprintf(stdout, "%#jx", 6171161506Sken (intmax_t)scsi_8btou64(tmp_lun)); 6172161506Sken no_more = 1; 6173161506Sken } else { 6174161506Sken fprintf(stderr, "Unknown Extended LUN" 6175161506Sken "Address method %#x, length " 6176161506Sken "code %#x", eam_code, 6177161506Sken field_len_code); 6178161506Sken no_more = 1; 6179161506Sken } 6180161506Sken break; 6181161506Sken } 6182161506Sken default: 6183161506Sken fprintf(stderr, "Unknown LUN address method " 6184161506Sken "%#x\n", lundata->luns[i].lundata[0] & 6185161506Sken RPL_LUNDATA_ATYP_MASK); 6186161506Sken break; 6187161506Sken } 6188161506Sken /* 6189161506Sken * For the flat addressing method, there are no 6190161506Sken * other levels after it. 6191161506Sken */ 6192161506Sken if (no_more != 0) 6193161506Sken break; 6194161506Sken } 6195161506Sken fprintf(stdout, "\n"); 6196161506Sken } 6197161506Sken 6198161506Skenbailout: 6199161506Sken 6200161506Sken cam_freeccb(ccb); 6201161506Sken 6202161506Sken free(lundata); 6203161506Sken 6204161506Sken return (retval); 6205161506Sken} 6206161506Sken 6207172093Skenstatic int 6208172093Skenscsireadcapacity(struct cam_device *device, int argc, char **argv, 6209172093Sken char *combinedopt, int retry_count, int timeout) 6210172093Sken{ 6211172093Sken union ccb *ccb; 6212172093Sken int blocksizeonly, humanize, numblocks, quiet, sizeonly, baseten; 6213172093Sken struct scsi_read_capacity_data rcap; 6214172093Sken struct scsi_read_capacity_data_long rcaplong; 6215172093Sken uint64_t maxsector; 6216172093Sken uint32_t block_len; 6217172093Sken int retval; 6218172093Sken int c; 6219172093Sken 6220172093Sken blocksizeonly = 0; 6221172093Sken humanize = 0; 6222172093Sken numblocks = 0; 6223172093Sken quiet = 0; 6224172093Sken sizeonly = 0; 6225172093Sken baseten = 0; 6226172093Sken retval = 0; 6227172093Sken 6228172093Sken ccb = cam_getccb(device); 6229172093Sken 6230172093Sken if (ccb == NULL) { 6231172093Sken warnx("%s: error allocating ccb", __func__); 6232172093Sken return (1); 6233172093Sken } 6234172093Sken 6235172093Sken bzero(&(&ccb->ccb_h)[1], 6236172093Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 6237172093Sken 6238172093Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 6239172093Sken switch (c) { 6240172093Sken case 'b': 6241172093Sken blocksizeonly++; 6242172093Sken break; 6243172093Sken case 'h': 6244172093Sken humanize++; 6245172093Sken baseten = 0; 6246172093Sken break; 6247172093Sken case 'H': 6248172093Sken humanize++; 6249172093Sken baseten++; 6250172093Sken break; 6251172093Sken case 'N': 6252172093Sken numblocks++; 6253172093Sken break; 6254172093Sken case 'q': 6255172093Sken quiet++; 6256172093Sken break; 6257172093Sken case 's': 6258172093Sken sizeonly++; 6259172093Sken break; 6260172093Sken default: 6261172093Sken break; 6262172093Sken } 6263172093Sken } 6264172093Sken 6265172093Sken if ((blocksizeonly != 0) 6266172093Sken && (numblocks != 0)) { 6267172093Sken warnx("%s: you can only specify one of -b or -N", __func__); 6268172093Sken retval = 1; 6269172093Sken goto bailout; 6270172093Sken } 6271172093Sken 6272172093Sken if ((blocksizeonly != 0) 6273172093Sken && (sizeonly != 0)) { 6274172093Sken warnx("%s: you can only specify one of -b or -s", __func__); 6275172093Sken retval = 1; 6276172093Sken goto bailout; 6277172093Sken } 6278172093Sken 6279172093Sken if ((humanize != 0) 6280172093Sken && (quiet != 0)) { 6281172093Sken warnx("%s: you can only specify one of -h/-H or -q", __func__); 6282172093Sken retval = 1; 6283172093Sken goto bailout; 6284172093Sken } 6285172093Sken 6286172093Sken if ((humanize != 0) 6287172093Sken && (blocksizeonly != 0)) { 6288172093Sken warnx("%s: you can only specify one of -h/-H or -b", __func__); 6289172093Sken retval = 1; 6290172093Sken goto bailout; 6291172093Sken } 6292172093Sken 6293172093Sken scsi_read_capacity(&ccb->csio, 6294172093Sken /*retries*/ retry_count, 6295172093Sken /*cbfcnp*/ NULL, 6296172093Sken /*tag_action*/ MSG_SIMPLE_Q_TAG, 6297172093Sken &rcap, 6298172093Sken SSD_FULL_SIZE, 6299172093Sken /*timeout*/ timeout ? timeout : 5000); 6300172093Sken 6301172093Sken /* Disable freezing the device queue */ 6302172093Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 6303172093Sken 6304172093Sken if (arglist & CAM_ARG_ERR_RECOVER) 6305172093Sken ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 6306172093Sken 6307172093Sken if (cam_send_ccb(device, ccb) < 0) { 6308172093Sken warn("error sending READ CAPACITY command"); 6309172093Sken 6310172093Sken if (arglist & CAM_ARG_VERBOSE) 6311172093Sken cam_error_print(device, ccb, CAM_ESF_ALL, 6312172093Sken CAM_EPF_ALL, stderr); 6313172093Sken 6314172093Sken retval = 1; 6315172093Sken goto bailout; 6316172093Sken } 6317172093Sken 6318172093Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 6319172093Sken cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); 6320172093Sken retval = 1; 6321172093Sken goto bailout; 6322172093Sken } 6323172093Sken 6324172093Sken maxsector = scsi_4btoul(rcap.addr); 6325172093Sken block_len = scsi_4btoul(rcap.length); 6326172093Sken 6327172093Sken /* 6328172093Sken * A last block of 2^32-1 means that the true capacity is over 2TB, 6329172093Sken * and we need to issue the long READ CAPACITY to get the real 6330172093Sken * capacity. Otherwise, we're all set. 6331172093Sken */ 6332172093Sken if (maxsector != 0xffffffff) 6333172093Sken goto do_print; 6334172093Sken 6335172093Sken scsi_read_capacity_16(&ccb->csio, 6336172093Sken /*retries*/ retry_count, 6337172093Sken /*cbfcnp*/ NULL, 6338172093Sken /*tag_action*/ MSG_SIMPLE_Q_TAG, 6339172093Sken /*lba*/ 0, 6340172093Sken /*reladdr*/ 0, 6341172093Sken /*pmi*/ 0, 6342230590Sken /*rcap_buf*/ (uint8_t *)&rcaplong, 6343230590Sken /*rcap_buf_len*/ sizeof(rcaplong), 6344172093Sken /*sense_len*/ SSD_FULL_SIZE, 6345172093Sken /*timeout*/ timeout ? timeout : 5000); 6346172093Sken 6347172093Sken /* Disable freezing the device queue */ 6348172093Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 6349172093Sken 6350172093Sken if (arglist & CAM_ARG_ERR_RECOVER) 6351172093Sken ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 6352172093Sken 6353172093Sken if (cam_send_ccb(device, ccb) < 0) { 6354172093Sken warn("error sending READ CAPACITY (16) command"); 6355172093Sken 6356172093Sken if (arglist & CAM_ARG_VERBOSE) 6357172093Sken cam_error_print(device, ccb, CAM_ESF_ALL, 6358172093Sken CAM_EPF_ALL, stderr); 6359172093Sken 6360172093Sken retval = 1; 6361172093Sken goto bailout; 6362172093Sken } 6363172093Sken 6364172093Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 6365172093Sken cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); 6366172093Sken retval = 1; 6367172093Sken goto bailout; 6368172093Sken } 6369172093Sken 6370172093Sken maxsector = scsi_8btou64(rcaplong.addr); 6371172093Sken block_len = scsi_4btoul(rcaplong.length); 6372172093Sken 6373172093Skendo_print: 6374172093Sken if (blocksizeonly == 0) { 6375172093Sken /* 6376172093Sken * Humanize implies !quiet, and also implies numblocks. 6377172093Sken */ 6378172093Sken if (humanize != 0) { 6379172093Sken char tmpstr[6]; 6380172093Sken int64_t tmpbytes; 6381172093Sken int ret; 6382172093Sken 6383172093Sken tmpbytes = (maxsector + 1) * block_len; 6384172093Sken ret = humanize_number(tmpstr, sizeof(tmpstr), 6385172093Sken tmpbytes, "", HN_AUTOSCALE, 6386172093Sken HN_B | HN_DECIMAL | 6387172093Sken ((baseten != 0) ? 6388172093Sken HN_DIVISOR_1000 : 0)); 6389172093Sken if (ret == -1) { 6390172093Sken warnx("%s: humanize_number failed!", __func__); 6391172093Sken retval = 1; 6392172093Sken goto bailout; 6393172093Sken } 6394172093Sken fprintf(stdout, "Device Size: %s%s", tmpstr, 6395172093Sken (sizeonly == 0) ? ", " : "\n"); 6396172093Sken } else if (numblocks != 0) { 6397172093Sken fprintf(stdout, "%s%ju%s", (quiet == 0) ? 6398172093Sken "Blocks: " : "", (uintmax_t)maxsector + 1, 6399172093Sken (sizeonly == 0) ? ", " : "\n"); 6400172093Sken } else { 6401172093Sken fprintf(stdout, "%s%ju%s", (quiet == 0) ? 6402172093Sken "Last Block: " : "", (uintmax_t)maxsector, 6403172093Sken (sizeonly == 0) ? ", " : "\n"); 6404172093Sken } 6405172093Sken } 6406172093Sken if (sizeonly == 0) 6407172093Sken fprintf(stdout, "%s%u%s\n", (quiet == 0) ? 6408172093Sken "Block Length: " : "", block_len, (quiet == 0) ? 6409172093Sken " bytes" : ""); 6410172093Skenbailout: 6411172093Sken cam_freeccb(ccb); 6412172093Sken 6413172093Sken return (retval); 6414172093Sken} 6415172093Sken 6416199079Smavstatic int 6417216088Skensmpcmd(struct cam_device *device, int argc, char **argv, char *combinedopt, 6418216088Sken int retry_count, int timeout) 6419216088Sken{ 6420239059Sdim int c, error = 0; 6421216088Sken union ccb *ccb; 6422216088Sken uint8_t *smp_request = NULL, *smp_response = NULL; 6423216088Sken int request_size = 0, response_size = 0; 6424216088Sken int fd_request = 0, fd_response = 0; 6425216088Sken char *datastr = NULL; 6426216088Sken struct get_hook hook; 6427216088Sken int retval; 6428216088Sken int flags = 0; 6429216088Sken 6430216088Sken /* 6431216088Sken * Note that at the moment we don't support sending SMP CCBs to 6432216088Sken * devices that aren't probed by CAM. 6433216088Sken */ 6434216088Sken ccb = cam_getccb(device); 6435216088Sken if (ccb == NULL) { 6436216088Sken warnx("%s: error allocating CCB", __func__); 6437216088Sken return (1); 6438216088Sken } 6439216088Sken 6440216088Sken bzero(&(&ccb->ccb_h)[1], 6441216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 6442216088Sken 6443216088Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 6444216088Sken switch (c) { 6445216088Sken case 'R': 6446216088Sken arglist |= CAM_ARG_CMD_IN; 6447216088Sken response_size = strtol(optarg, NULL, 0); 6448216088Sken if (response_size <= 0) { 6449216088Sken warnx("invalid number of response bytes %d", 6450216088Sken response_size); 6451216088Sken error = 1; 6452216088Sken goto smpcmd_bailout; 6453216088Sken } 6454216088Sken hook.argc = argc - optind; 6455216088Sken hook.argv = argv + optind; 6456216088Sken hook.got = 0; 6457216088Sken optind++; 6458216088Sken datastr = cget(&hook, NULL); 6459216088Sken /* 6460216088Sken * If the user supplied "-" instead of a format, he 6461216088Sken * wants the data to be written to stdout. 6462216088Sken */ 6463216088Sken if ((datastr != NULL) 6464216088Sken && (datastr[0] == '-')) 6465216088Sken fd_response = 1; 6466216088Sken 6467216088Sken smp_response = (u_int8_t *)malloc(response_size); 6468216088Sken if (smp_response == NULL) { 6469216088Sken warn("can't malloc memory for SMP response"); 6470216088Sken error = 1; 6471216088Sken goto smpcmd_bailout; 6472216088Sken } 6473216088Sken break; 6474216088Sken case 'r': 6475216088Sken arglist |= CAM_ARG_CMD_OUT; 6476216088Sken request_size = strtol(optarg, NULL, 0); 6477216088Sken if (request_size <= 0) { 6478216088Sken warnx("invalid number of request bytes %d", 6479216088Sken request_size); 6480216088Sken error = 1; 6481216088Sken goto smpcmd_bailout; 6482216088Sken } 6483216088Sken hook.argc = argc - optind; 6484216088Sken hook.argv = argv + optind; 6485216088Sken hook.got = 0; 6486216088Sken datastr = cget(&hook, NULL); 6487216088Sken smp_request = (u_int8_t *)malloc(request_size); 6488216088Sken if (smp_request == NULL) { 6489216088Sken warn("can't malloc memory for SMP request"); 6490216088Sken error = 1; 6491216088Sken goto smpcmd_bailout; 6492216088Sken } 6493216088Sken bzero(smp_request, request_size); 6494216088Sken /* 6495216088Sken * If the user supplied "-" instead of a format, he 6496216088Sken * wants the data to be read from stdin. 6497216088Sken */ 6498216088Sken if ((datastr != NULL) 6499216088Sken && (datastr[0] == '-')) 6500216088Sken fd_request = 1; 6501216088Sken else 6502216088Sken buff_encode_visit(smp_request, request_size, 6503216088Sken datastr, 6504216088Sken iget, &hook); 6505216088Sken optind += hook.got; 6506216088Sken break; 6507216088Sken default: 6508216088Sken break; 6509216088Sken } 6510216088Sken } 6511216088Sken 6512216088Sken /* 6513216088Sken * If fd_data is set, and we're writing to the device, we need to 6514216088Sken * read the data the user wants written from stdin. 6515216088Sken */ 6516216088Sken if ((fd_request == 1) && (arglist & CAM_ARG_CMD_OUT)) { 6517216088Sken ssize_t amt_read; 6518216088Sken int amt_to_read = request_size; 6519216088Sken u_int8_t *buf_ptr = smp_request; 6520216088Sken 6521216088Sken for (amt_read = 0; amt_to_read > 0; 6522216088Sken amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) { 6523216088Sken if (amt_read == -1) { 6524216088Sken warn("error reading data from stdin"); 6525216088Sken error = 1; 6526216088Sken goto smpcmd_bailout; 6527216088Sken } 6528216088Sken amt_to_read -= amt_read; 6529216088Sken buf_ptr += amt_read; 6530216088Sken } 6531216088Sken } 6532216088Sken 6533216088Sken if (((arglist & CAM_ARG_CMD_IN) == 0) 6534216088Sken || ((arglist & CAM_ARG_CMD_OUT) == 0)) { 6535216088Sken warnx("%s: need both the request (-r) and response (-R) " 6536216088Sken "arguments", __func__); 6537216088Sken error = 1; 6538216088Sken goto smpcmd_bailout; 6539216088Sken } 6540216088Sken 6541216088Sken flags |= CAM_DEV_QFRZDIS; 6542216088Sken 6543216088Sken cam_fill_smpio(&ccb->smpio, 6544216088Sken /*retries*/ retry_count, 6545216088Sken /*cbfcnp*/ NULL, 6546216088Sken /*flags*/ flags, 6547216088Sken /*smp_request*/ smp_request, 6548216088Sken /*smp_request_len*/ request_size, 6549216088Sken /*smp_response*/ smp_response, 6550216088Sken /*smp_response_len*/ response_size, 6551216088Sken /*timeout*/ timeout ? timeout : 5000); 6552216088Sken 6553216088Sken ccb->smpio.flags = SMP_FLAG_NONE; 6554216088Sken 6555216088Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 6556216088Sken || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 6557228602Sdim const char warnstr[] = "error sending command"; 6558216088Sken 6559216088Sken if (retval < 0) 6560216088Sken warn(warnstr); 6561216088Sken else 6562216088Sken warnx(warnstr); 6563216088Sken 6564216088Sken if (arglist & CAM_ARG_VERBOSE) { 6565216088Sken cam_error_print(device, ccb, CAM_ESF_ALL, 6566216088Sken CAM_EPF_ALL, stderr); 6567216088Sken } 6568216088Sken } 6569216088Sken 6570216088Sken if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 6571216088Sken && (response_size > 0)) { 6572216088Sken if (fd_response == 0) { 6573216088Sken buff_decode_visit(smp_response, response_size, 6574216088Sken datastr, arg_put, NULL); 6575216088Sken fprintf(stdout, "\n"); 6576216088Sken } else { 6577216088Sken ssize_t amt_written; 6578216088Sken int amt_to_write = response_size; 6579216088Sken u_int8_t *buf_ptr = smp_response; 6580216088Sken 6581216088Sken for (amt_written = 0; (amt_to_write > 0) && 6582216088Sken (amt_written = write(STDOUT_FILENO, buf_ptr, 6583216088Sken amt_to_write)) > 0;){ 6584216088Sken amt_to_write -= amt_written; 6585216088Sken buf_ptr += amt_written; 6586216088Sken } 6587216088Sken if (amt_written == -1) { 6588216088Sken warn("error writing data to stdout"); 6589216088Sken error = 1; 6590216088Sken goto smpcmd_bailout; 6591216088Sken } else if ((amt_written == 0) 6592216088Sken && (amt_to_write > 0)) { 6593216088Sken warnx("only wrote %u bytes out of %u", 6594216088Sken response_size - amt_to_write, 6595216088Sken response_size); 6596216088Sken } 6597216088Sken } 6598216088Sken } 6599216088Skensmpcmd_bailout: 6600216088Sken if (ccb != NULL) 6601216088Sken cam_freeccb(ccb); 6602216088Sken 6603216088Sken if (smp_request != NULL) 6604216088Sken free(smp_request); 6605216088Sken 6606216088Sken if (smp_response != NULL) 6607216088Sken free(smp_response); 6608216088Sken 6609216088Sken return (error); 6610216088Sken} 6611216088Sken 6612216088Skenstatic int 6613216088Skensmpreportgeneral(struct cam_device *device, int argc, char **argv, 6614216088Sken char *combinedopt, int retry_count, int timeout) 6615216088Sken{ 6616216088Sken union ccb *ccb; 6617216088Sken struct smp_report_general_request *request = NULL; 6618216088Sken struct smp_report_general_response *response = NULL; 6619216088Sken struct sbuf *sb = NULL; 6620216088Sken int error = 0; 6621216088Sken int c, long_response = 0; 6622216088Sken int retval; 6623216088Sken 6624216088Sken /* 6625216088Sken * Note that at the moment we don't support sending SMP CCBs to 6626216088Sken * devices that aren't probed by CAM. 6627216088Sken */ 6628216088Sken ccb = cam_getccb(device); 6629216088Sken if (ccb == NULL) { 6630216088Sken warnx("%s: error allocating CCB", __func__); 6631216088Sken return (1); 6632216088Sken } 6633216088Sken 6634216088Sken bzero(&(&ccb->ccb_h)[1], 6635216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 6636216088Sken 6637216088Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 6638216088Sken switch (c) { 6639216088Sken case 'l': 6640216088Sken long_response = 1; 6641216088Sken break; 6642216088Sken default: 6643216088Sken break; 6644216088Sken } 6645216088Sken } 6646216088Sken request = malloc(sizeof(*request)); 6647216088Sken if (request == NULL) { 6648216088Sken warn("%s: unable to allocate %zd bytes", __func__, 6649216088Sken sizeof(*request)); 6650216088Sken error = 1; 6651216088Sken goto bailout; 6652216088Sken } 6653216088Sken 6654216088Sken response = malloc(sizeof(*response)); 6655216088Sken if (response == NULL) { 6656216088Sken warn("%s: unable to allocate %zd bytes", __func__, 6657216088Sken sizeof(*response)); 6658216088Sken error = 1; 6659216088Sken goto bailout; 6660216088Sken } 6661216088Sken 6662216088Skentry_long: 6663216088Sken smp_report_general(&ccb->smpio, 6664216088Sken retry_count, 6665216088Sken /*cbfcnp*/ NULL, 6666216088Sken request, 6667216088Sken /*request_len*/ sizeof(*request), 6668216088Sken (uint8_t *)response, 6669216088Sken /*response_len*/ sizeof(*response), 6670216088Sken /*long_response*/ long_response, 6671216088Sken timeout); 6672216088Sken 6673216088Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 6674216088Sken || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 6675228602Sdim const char warnstr[] = "error sending command"; 6676216088Sken 6677216088Sken if (retval < 0) 6678216088Sken warn(warnstr); 6679216088Sken else 6680216088Sken warnx(warnstr); 6681216088Sken 6682216088Sken if (arglist & CAM_ARG_VERBOSE) { 6683216088Sken cam_error_print(device, ccb, CAM_ESF_ALL, 6684216088Sken CAM_EPF_ALL, stderr); 6685216088Sken } 6686216088Sken error = 1; 6687216088Sken goto bailout; 6688216088Sken } 6689216088Sken 6690216088Sken /* 6691216088Sken * If the device supports the long response bit, try again and see 6692216088Sken * if we can get all of the data. 6693216088Sken */ 6694216088Sken if ((response->long_response & SMP_RG_LONG_RESPONSE) 6695216088Sken && (long_response == 0)) { 6696216088Sken ccb->ccb_h.status = CAM_REQ_INPROG; 6697216088Sken bzero(&(&ccb->ccb_h)[1], 6698216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 6699216088Sken long_response = 1; 6700216088Sken goto try_long; 6701216088Sken } 6702216088Sken 6703216088Sken /* 6704216088Sken * XXX KDM detect and decode SMP errors here. 6705216088Sken */ 6706216088Sken sb = sbuf_new_auto(); 6707216088Sken if (sb == NULL) { 6708216088Sken warnx("%s: error allocating sbuf", __func__); 6709216088Sken goto bailout; 6710216088Sken } 6711216088Sken 6712216088Sken smp_report_general_sbuf(response, sizeof(*response), sb); 6713216088Sken 6714239612Sjh if (sbuf_finish(sb) != 0) { 6715239612Sjh warnx("%s: sbuf_finish", __func__); 6716239612Sjh goto bailout; 6717239612Sjh } 6718216088Sken 6719216088Sken printf("%s", sbuf_data(sb)); 6720216088Sken 6721216088Skenbailout: 6722216088Sken if (ccb != NULL) 6723216088Sken cam_freeccb(ccb); 6724216088Sken 6725216088Sken if (request != NULL) 6726216088Sken free(request); 6727216088Sken 6728216088Sken if (response != NULL) 6729216088Sken free(response); 6730216088Sken 6731216088Sken if (sb != NULL) 6732216088Sken sbuf_delete(sb); 6733216088Sken 6734216088Sken return (error); 6735216088Sken} 6736216088Sken 6737227081Sedstatic struct camcontrol_opts phy_ops[] = { 6738216088Sken {"nop", SMP_PC_PHY_OP_NOP, CAM_ARG_NONE, NULL}, 6739216088Sken {"linkreset", SMP_PC_PHY_OP_LINK_RESET, CAM_ARG_NONE, NULL}, 6740216088Sken {"hardreset", SMP_PC_PHY_OP_HARD_RESET, CAM_ARG_NONE, NULL}, 6741216088Sken {"disable", SMP_PC_PHY_OP_DISABLE, CAM_ARG_NONE, NULL}, 6742216088Sken {"clearerrlog", SMP_PC_PHY_OP_CLEAR_ERR_LOG, CAM_ARG_NONE, NULL}, 6743216088Sken {"clearaffiliation", SMP_PC_PHY_OP_CLEAR_AFFILIATON, CAM_ARG_NONE,NULL}, 6744216088Sken {"sataportsel", SMP_PC_PHY_OP_TRANS_SATA_PSS, CAM_ARG_NONE, NULL}, 6745216088Sken {"clearitnl", SMP_PC_PHY_OP_CLEAR_STP_ITN_LS, CAM_ARG_NONE, NULL}, 6746216088Sken {"setdevname", SMP_PC_PHY_OP_SET_ATT_DEV_NAME, CAM_ARG_NONE, NULL}, 6747216088Sken {NULL, 0, 0, NULL} 6748216088Sken}; 6749216088Sken 6750216088Skenstatic int 6751216088Skensmpphycontrol(struct cam_device *device, int argc, char **argv, 6752216088Sken char *combinedopt, int retry_count, int timeout) 6753216088Sken{ 6754216088Sken union ccb *ccb; 6755216088Sken struct smp_phy_control_request *request = NULL; 6756216088Sken struct smp_phy_control_response *response = NULL; 6757216088Sken int long_response = 0; 6758216088Sken int retval = 0; 6759216088Sken int phy = -1; 6760216088Sken uint32_t phy_operation = SMP_PC_PHY_OP_NOP; 6761216088Sken int phy_op_set = 0; 6762216088Sken uint64_t attached_dev_name = 0; 6763216088Sken int dev_name_set = 0; 6764216088Sken uint32_t min_plr = 0, max_plr = 0; 6765216088Sken uint32_t pp_timeout_val = 0; 6766216088Sken int slumber_partial = 0; 6767216088Sken int set_pp_timeout_val = 0; 6768216088Sken int c; 6769216088Sken 6770216088Sken /* 6771216088Sken * Note that at the moment we don't support sending SMP CCBs to 6772216088Sken * devices that aren't probed by CAM. 6773216088Sken */ 6774216088Sken ccb = cam_getccb(device); 6775216088Sken if (ccb == NULL) { 6776216088Sken warnx("%s: error allocating CCB", __func__); 6777216088Sken return (1); 6778216088Sken } 6779216088Sken 6780216088Sken bzero(&(&ccb->ccb_h)[1], 6781216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 6782216088Sken 6783216088Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 6784216088Sken switch (c) { 6785216088Sken case 'a': 6786216088Sken case 'A': 6787216088Sken case 's': 6788216088Sken case 'S': { 6789216088Sken int enable = -1; 6790216088Sken 6791216088Sken if (strcasecmp(optarg, "enable") == 0) 6792216088Sken enable = 1; 6793216088Sken else if (strcasecmp(optarg, "disable") == 0) 6794216088Sken enable = 2; 6795216088Sken else { 6796216088Sken warnx("%s: Invalid argument %s", __func__, 6797216088Sken optarg); 6798216088Sken retval = 1; 6799216088Sken goto bailout; 6800216088Sken } 6801216088Sken switch (c) { 6802216088Sken case 's': 6803216088Sken slumber_partial |= enable << 6804216088Sken SMP_PC_SAS_SLUMBER_SHIFT; 6805216088Sken break; 6806216088Sken case 'S': 6807216088Sken slumber_partial |= enable << 6808216088Sken SMP_PC_SAS_PARTIAL_SHIFT; 6809216088Sken break; 6810216088Sken case 'a': 6811216088Sken slumber_partial |= enable << 6812216088Sken SMP_PC_SATA_SLUMBER_SHIFT; 6813216088Sken break; 6814216088Sken case 'A': 6815216088Sken slumber_partial |= enable << 6816216088Sken SMP_PC_SATA_PARTIAL_SHIFT; 6817216088Sken break; 6818216088Sken default: 6819216088Sken warnx("%s: programmer error", __func__); 6820216088Sken retval = 1; 6821216088Sken goto bailout; 6822216088Sken break; /*NOTREACHED*/ 6823216088Sken } 6824216088Sken break; 6825216088Sken } 6826216088Sken case 'd': 6827216088Sken attached_dev_name = (uintmax_t)strtoumax(optarg, 6828216088Sken NULL,0); 6829216088Sken dev_name_set = 1; 6830216088Sken break; 6831216088Sken case 'l': 6832216088Sken long_response = 1; 6833216088Sken break; 6834216088Sken case 'm': 6835216088Sken /* 6836216088Sken * We don't do extensive checking here, so this 6837216088Sken * will continue to work when new speeds come out. 6838216088Sken */ 6839216088Sken min_plr = strtoul(optarg, NULL, 0); 6840216088Sken if ((min_plr == 0) 6841216088Sken || (min_plr > 0xf)) { 6842216088Sken warnx("%s: invalid link rate %x", 6843216088Sken __func__, min_plr); 6844216088Sken retval = 1; 6845216088Sken goto bailout; 6846216088Sken } 6847216088Sken break; 6848216088Sken case 'M': 6849216088Sken /* 6850216088Sken * We don't do extensive checking here, so this 6851216088Sken * will continue to work when new speeds come out. 6852216088Sken */ 6853216088Sken max_plr = strtoul(optarg, NULL, 0); 6854216088Sken if ((max_plr == 0) 6855216088Sken || (max_plr > 0xf)) { 6856216088Sken warnx("%s: invalid link rate %x", 6857216088Sken __func__, max_plr); 6858216088Sken retval = 1; 6859216088Sken goto bailout; 6860216088Sken } 6861216088Sken break; 6862216088Sken case 'o': { 6863216088Sken camcontrol_optret optreturn; 6864216088Sken cam_argmask argnums; 6865216088Sken const char *subopt; 6866216088Sken 6867216088Sken if (phy_op_set != 0) { 6868216088Sken warnx("%s: only one phy operation argument " 6869216088Sken "(-o) allowed", __func__); 6870216088Sken retval = 1; 6871216088Sken goto bailout; 6872216088Sken } 6873216088Sken 6874216088Sken phy_op_set = 1; 6875216088Sken 6876216088Sken /* 6877216088Sken * Allow the user to specify the phy operation 6878216088Sken * numerically, as well as with a name. This will 6879216088Sken * future-proof it a bit, so options that are added 6880216088Sken * in future specs can be used. 6881216088Sken */ 6882216088Sken if (isdigit(optarg[0])) { 6883216088Sken phy_operation = strtoul(optarg, NULL, 0); 6884216088Sken if ((phy_operation == 0) 6885216088Sken || (phy_operation > 0xff)) { 6886216088Sken warnx("%s: invalid phy operation %#x", 6887216088Sken __func__, phy_operation); 6888216088Sken retval = 1; 6889216088Sken goto bailout; 6890216088Sken } 6891216088Sken break; 6892216088Sken } 6893216088Sken optreturn = getoption(phy_ops, optarg, &phy_operation, 6894216088Sken &argnums, &subopt); 6895216088Sken 6896216088Sken if (optreturn == CC_OR_AMBIGUOUS) { 6897216088Sken warnx("%s: ambiguous option %s", __func__, 6898216088Sken optarg); 6899216088Sken usage(0); 6900216088Sken retval = 1; 6901216088Sken goto bailout; 6902216088Sken } else if (optreturn == CC_OR_NOT_FOUND) { 6903216088Sken warnx("%s: option %s not found", __func__, 6904216088Sken optarg); 6905216088Sken usage(0); 6906216088Sken retval = 1; 6907216088Sken goto bailout; 6908216088Sken } 6909216088Sken break; 6910216088Sken } 6911216088Sken case 'p': 6912216088Sken phy = atoi(optarg); 6913216088Sken break; 6914216088Sken case 'T': 6915216088Sken pp_timeout_val = strtoul(optarg, NULL, 0); 6916216088Sken if (pp_timeout_val > 15) { 6917216088Sken warnx("%s: invalid partial pathway timeout " 6918216088Sken "value %u, need a value less than 16", 6919216088Sken __func__, pp_timeout_val); 6920216088Sken retval = 1; 6921216088Sken goto bailout; 6922216088Sken } 6923216088Sken set_pp_timeout_val = 1; 6924216088Sken break; 6925216088Sken default: 6926216088Sken break; 6927216088Sken } 6928216088Sken } 6929216088Sken 6930216088Sken if (phy == -1) { 6931216088Sken warnx("%s: a PHY (-p phy) argument is required",__func__); 6932216088Sken retval = 1; 6933216088Sken goto bailout; 6934216088Sken } 6935216088Sken 6936216088Sken if (((dev_name_set != 0) 6937216088Sken && (phy_operation != SMP_PC_PHY_OP_SET_ATT_DEV_NAME)) 6938216088Sken || ((phy_operation == SMP_PC_PHY_OP_SET_ATT_DEV_NAME) 6939216088Sken && (dev_name_set == 0))) { 6940216088Sken warnx("%s: -d name and -o setdevname arguments both " 6941216088Sken "required to set device name", __func__); 6942216088Sken retval = 1; 6943216088Sken goto bailout; 6944216088Sken } 6945216088Sken 6946216088Sken request = malloc(sizeof(*request)); 6947216088Sken if (request == NULL) { 6948216088Sken warn("%s: unable to allocate %zd bytes", __func__, 6949216088Sken sizeof(*request)); 6950216088Sken retval = 1; 6951216088Sken goto bailout; 6952216088Sken } 6953216088Sken 6954216088Sken response = malloc(sizeof(*response)); 6955216088Sken if (response == NULL) { 6956216088Sken warn("%s: unable to allocate %zd bytes", __func__, 6957216088Sken sizeof(*request)); 6958216088Sken retval = 1; 6959216088Sken goto bailout; 6960216088Sken } 6961216088Sken 6962216088Sken smp_phy_control(&ccb->smpio, 6963216088Sken retry_count, 6964216088Sken /*cbfcnp*/ NULL, 6965216088Sken request, 6966216088Sken sizeof(*request), 6967216088Sken (uint8_t *)response, 6968216088Sken sizeof(*response), 6969216088Sken long_response, 6970216088Sken /*expected_exp_change_count*/ 0, 6971216088Sken phy, 6972216088Sken phy_operation, 6973216088Sken (set_pp_timeout_val != 0) ? 1 : 0, 6974216088Sken attached_dev_name, 6975216088Sken min_plr, 6976216088Sken max_plr, 6977216088Sken slumber_partial, 6978216088Sken pp_timeout_val, 6979216088Sken timeout); 6980216088Sken 6981216088Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 6982216088Sken || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 6983228602Sdim const char warnstr[] = "error sending command"; 6984216088Sken 6985216088Sken if (retval < 0) 6986216088Sken warn(warnstr); 6987216088Sken else 6988216088Sken warnx(warnstr); 6989216088Sken 6990216088Sken if (arglist & CAM_ARG_VERBOSE) { 6991216088Sken /* 6992216088Sken * Use CAM_EPF_NORMAL so we only get one line of 6993216088Sken * SMP command decoding. 6994216088Sken */ 6995216088Sken cam_error_print(device, ccb, CAM_ESF_ALL, 6996216088Sken CAM_EPF_NORMAL, stderr); 6997216088Sken } 6998216088Sken retval = 1; 6999216088Sken goto bailout; 7000216088Sken } 7001216088Sken 7002216088Sken /* XXX KDM print out something here for success? */ 7003216088Skenbailout: 7004216088Sken if (ccb != NULL) 7005216088Sken cam_freeccb(ccb); 7006216088Sken 7007216088Sken if (request != NULL) 7008216088Sken free(request); 7009216088Sken 7010216088Sken if (response != NULL) 7011216088Sken free(response); 7012216088Sken 7013216088Sken return (retval); 7014216088Sken} 7015216088Sken 7016216088Skenstatic int 7017216088Skensmpmaninfo(struct cam_device *device, int argc, char **argv, 7018216088Sken char *combinedopt, int retry_count, int timeout) 7019216088Sken{ 7020216088Sken union ccb *ccb; 7021216088Sken struct smp_report_manuf_info_request request; 7022216088Sken struct smp_report_manuf_info_response response; 7023216088Sken struct sbuf *sb = NULL; 7024216088Sken int long_response = 0; 7025216088Sken int retval = 0; 7026216088Sken int c; 7027216088Sken 7028216088Sken /* 7029216088Sken * Note that at the moment we don't support sending SMP CCBs to 7030216088Sken * devices that aren't probed by CAM. 7031216088Sken */ 7032216088Sken ccb = cam_getccb(device); 7033216088Sken if (ccb == NULL) { 7034216088Sken warnx("%s: error allocating CCB", __func__); 7035216088Sken return (1); 7036216088Sken } 7037216088Sken 7038216088Sken bzero(&(&ccb->ccb_h)[1], 7039216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 7040216088Sken 7041216088Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 7042216088Sken switch (c) { 7043216088Sken case 'l': 7044216088Sken long_response = 1; 7045216088Sken break; 7046216088Sken default: 7047216088Sken break; 7048216088Sken } 7049216088Sken } 7050216088Sken bzero(&request, sizeof(request)); 7051216088Sken bzero(&response, sizeof(response)); 7052216088Sken 7053216088Sken smp_report_manuf_info(&ccb->smpio, 7054216088Sken retry_count, 7055216088Sken /*cbfcnp*/ NULL, 7056216088Sken &request, 7057216088Sken sizeof(request), 7058216088Sken (uint8_t *)&response, 7059216088Sken sizeof(response), 7060216088Sken long_response, 7061216088Sken timeout); 7062216088Sken 7063216088Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 7064216088Sken || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 7065228602Sdim const char warnstr[] = "error sending command"; 7066216088Sken 7067216088Sken if (retval < 0) 7068216088Sken warn(warnstr); 7069216088Sken else 7070216088Sken warnx(warnstr); 7071216088Sken 7072216088Sken if (arglist & CAM_ARG_VERBOSE) { 7073216088Sken cam_error_print(device, ccb, CAM_ESF_ALL, 7074216088Sken CAM_EPF_ALL, stderr); 7075216088Sken } 7076216088Sken retval = 1; 7077216088Sken goto bailout; 7078216088Sken } 7079216088Sken 7080216088Sken sb = sbuf_new_auto(); 7081216088Sken if (sb == NULL) { 7082216088Sken warnx("%s: error allocating sbuf", __func__); 7083216088Sken goto bailout; 7084216088Sken } 7085216088Sken 7086216088Sken smp_report_manuf_info_sbuf(&response, sizeof(response), sb); 7087216088Sken 7088239612Sjh if (sbuf_finish(sb) != 0) { 7089239612Sjh warnx("%s: sbuf_finish", __func__); 7090239612Sjh goto bailout; 7091239612Sjh } 7092216088Sken 7093216088Sken printf("%s", sbuf_data(sb)); 7094216088Sken 7095216088Skenbailout: 7096216088Sken 7097216088Sken if (ccb != NULL) 7098216088Sken cam_freeccb(ccb); 7099216088Sken 7100216088Sken if (sb != NULL) 7101216088Sken sbuf_delete(sb); 7102216088Sken 7103216088Sken return (retval); 7104216088Sken} 7105216088Sken 7106216088Skenstatic int 7107216088Skengetdevid(struct cam_devitem *item) 7108216088Sken{ 7109216088Sken int retval = 0; 7110216088Sken union ccb *ccb = NULL; 7111216088Sken 7112216088Sken struct cam_device *dev; 7113216088Sken 7114216088Sken dev = cam_open_btl(item->dev_match.path_id, 7115216088Sken item->dev_match.target_id, 7116216088Sken item->dev_match.target_lun, O_RDWR, NULL); 7117216088Sken 7118216088Sken if (dev == NULL) { 7119216088Sken warnx("%s", cam_errbuf); 7120216088Sken retval = 1; 7121216088Sken goto bailout; 7122216088Sken } 7123216088Sken 7124216361Sken item->device_id_len = 0; 7125216088Sken 7126216088Sken ccb = cam_getccb(dev); 7127216088Sken if (ccb == NULL) { 7128216088Sken warnx("%s: error allocating CCB", __func__); 7129216088Sken retval = 1; 7130216088Sken goto bailout; 7131216088Sken } 7132216088Sken 7133216088Sken bzero(&(&ccb->ccb_h)[1], 7134216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 7135216361Sken 7136216361Sken /* 7137216361Sken * On the first try, we just probe for the size of the data, and 7138216361Sken * then allocate that much memory and try again. 7139216361Sken */ 7140216361Skenretry: 7141223081Sgibbs ccb->ccb_h.func_code = XPT_DEV_ADVINFO; 7142216088Sken ccb->ccb_h.flags = CAM_DIR_IN; 7143223081Sgibbs ccb->cdai.flags = 0; 7144223081Sgibbs ccb->cdai.buftype = CDAI_TYPE_SCSI_DEVID; 7145223081Sgibbs ccb->cdai.bufsiz = item->device_id_len; 7146216361Sken if (item->device_id_len != 0) 7147223081Sgibbs ccb->cdai.buf = (uint8_t *)item->device_id; 7148216088Sken 7149216088Sken if (cam_send_ccb(dev, ccb) < 0) { 7150216088Sken warn("%s: error sending XPT_GDEV_ADVINFO CCB", __func__); 7151216088Sken retval = 1; 7152216088Sken goto bailout; 7153216088Sken } 7154216088Sken 7155216088Sken if (ccb->ccb_h.status != CAM_REQ_CMP) { 7156216088Sken warnx("%s: CAM status %#x", __func__, ccb->ccb_h.status); 7157216088Sken retval = 1; 7158216088Sken goto bailout; 7159216088Sken } 7160216088Sken 7161216361Sken if (item->device_id_len == 0) { 7162216361Sken /* 7163216361Sken * This is our first time through. Allocate the buffer, 7164216361Sken * and then go back to get the data. 7165216361Sken */ 7166223081Sgibbs if (ccb->cdai.provsiz == 0) { 7167216361Sken warnx("%s: invalid .provsiz field returned with " 7168216361Sken "XPT_GDEV_ADVINFO CCB", __func__); 7169216361Sken retval = 1; 7170216361Sken goto bailout; 7171216361Sken } 7172223081Sgibbs item->device_id_len = ccb->cdai.provsiz; 7173216361Sken item->device_id = malloc(item->device_id_len); 7174216361Sken if (item->device_id == NULL) { 7175216361Sken warn("%s: unable to allocate %d bytes", __func__, 7176216361Sken item->device_id_len); 7177216361Sken retval = 1; 7178216361Sken goto bailout; 7179216361Sken } 7180216361Sken ccb->ccb_h.status = CAM_REQ_INPROG; 7181216361Sken goto retry; 7182216361Sken } 7183216361Sken 7184216088Skenbailout: 7185216088Sken if (dev != NULL) 7186216088Sken cam_close_device(dev); 7187216088Sken 7188216088Sken if (ccb != NULL) 7189216088Sken cam_freeccb(ccb); 7190216088Sken 7191216088Sken return (retval); 7192216088Sken} 7193216088Sken 7194216088Sken/* 7195216088Sken * XXX KDM merge this code with getdevtree()? 7196216088Sken */ 7197216088Skenstatic int 7198216088Skenbuildbusdevlist(struct cam_devlist *devlist) 7199216088Sken{ 7200216088Sken union ccb ccb; 7201216088Sken int bufsize, fd = -1; 7202216088Sken struct dev_match_pattern *patterns; 7203216088Sken struct cam_devitem *item = NULL; 7204216088Sken int skip_device = 0; 7205216088Sken int retval = 0; 7206216088Sken 7207216088Sken if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) { 7208216088Sken warn("couldn't open %s", XPT_DEVICE); 7209216088Sken return(1); 7210216088Sken } 7211216088Sken 7212216088Sken bzero(&ccb, sizeof(union ccb)); 7213216088Sken 7214216088Sken ccb.ccb_h.path_id = CAM_XPT_PATH_ID; 7215216088Sken ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; 7216216088Sken ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; 7217216088Sken 7218216088Sken ccb.ccb_h.func_code = XPT_DEV_MATCH; 7219216088Sken bufsize = sizeof(struct dev_match_result) * 100; 7220216088Sken ccb.cdm.match_buf_len = bufsize; 7221216088Sken ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize); 7222216088Sken if (ccb.cdm.matches == NULL) { 7223216088Sken warnx("can't malloc memory for matches"); 7224216088Sken close(fd); 7225216088Sken return(1); 7226216088Sken } 7227216088Sken ccb.cdm.num_matches = 0; 7228216088Sken ccb.cdm.num_patterns = 2; 7229216088Sken ccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern) * 7230216088Sken ccb.cdm.num_patterns; 7231216088Sken 7232216088Sken patterns = (struct dev_match_pattern *)malloc(ccb.cdm.pattern_buf_len); 7233216088Sken if (patterns == NULL) { 7234216088Sken warnx("can't malloc memory for patterns"); 7235216088Sken retval = 1; 7236216088Sken goto bailout; 7237216088Sken } 7238216088Sken 7239216088Sken ccb.cdm.patterns = patterns; 7240216088Sken bzero(patterns, ccb.cdm.pattern_buf_len); 7241216088Sken 7242216088Sken patterns[0].type = DEV_MATCH_DEVICE; 7243216088Sken patterns[0].pattern.device_pattern.flags = DEV_MATCH_PATH; 7244216088Sken patterns[0].pattern.device_pattern.path_id = devlist->path_id; 7245216088Sken patterns[1].type = DEV_MATCH_PERIPH; 7246216088Sken patterns[1].pattern.periph_pattern.flags = PERIPH_MATCH_PATH; 7247216088Sken patterns[1].pattern.periph_pattern.path_id = devlist->path_id; 7248216088Sken 7249216088Sken /* 7250216088Sken * We do the ioctl multiple times if necessary, in case there are 7251216088Sken * more than 100 nodes in the EDT. 7252216088Sken */ 7253216088Sken do { 7254216088Sken unsigned int i; 7255216088Sken 7256216088Sken if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 7257216088Sken warn("error sending CAMIOCOMMAND ioctl"); 7258216088Sken retval = 1; 7259216088Sken goto bailout; 7260216088Sken } 7261216088Sken 7262216088Sken if ((ccb.ccb_h.status != CAM_REQ_CMP) 7263216088Sken || ((ccb.cdm.status != CAM_DEV_MATCH_LAST) 7264216088Sken && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { 7265216088Sken warnx("got CAM error %#x, CDM error %d\n", 7266216088Sken ccb.ccb_h.status, ccb.cdm.status); 7267216088Sken retval = 1; 7268216088Sken goto bailout; 7269216088Sken } 7270216088Sken 7271216088Sken for (i = 0; i < ccb.cdm.num_matches; i++) { 7272216088Sken switch (ccb.cdm.matches[i].type) { 7273216088Sken case DEV_MATCH_DEVICE: { 7274216088Sken struct device_match_result *dev_result; 7275216088Sken 7276216088Sken dev_result = 7277216088Sken &ccb.cdm.matches[i].result.device_result; 7278216088Sken 7279216361Sken if (dev_result->flags & 7280216361Sken DEV_RESULT_UNCONFIGURED) { 7281216088Sken skip_device = 1; 7282216088Sken break; 7283216088Sken } else 7284216088Sken skip_device = 0; 7285216088Sken 7286216088Sken item = malloc(sizeof(*item)); 7287216088Sken if (item == NULL) { 7288216088Sken warn("%s: unable to allocate %zd bytes", 7289216088Sken __func__, sizeof(*item)); 7290216088Sken retval = 1; 7291216088Sken goto bailout; 7292216088Sken } 7293216088Sken bzero(item, sizeof(*item)); 7294216088Sken bcopy(dev_result, &item->dev_match, 7295216088Sken sizeof(*dev_result)); 7296216088Sken STAILQ_INSERT_TAIL(&devlist->dev_queue, item, 7297216088Sken links); 7298216088Sken 7299216088Sken if (getdevid(item) != 0) { 7300216088Sken retval = 1; 7301216088Sken goto bailout; 7302216088Sken } 7303216088Sken break; 7304216088Sken } 7305216088Sken case DEV_MATCH_PERIPH: { 7306216088Sken struct periph_match_result *periph_result; 7307216088Sken 7308216088Sken periph_result = 7309216088Sken &ccb.cdm.matches[i].result.periph_result; 7310216088Sken 7311216088Sken if (skip_device != 0) 7312216088Sken break; 7313216088Sken item->num_periphs++; 7314216088Sken item->periph_matches = realloc( 7315216088Sken item->periph_matches, 7316216088Sken item->num_periphs * 7317216088Sken sizeof(struct periph_match_result)); 7318216088Sken if (item->periph_matches == NULL) { 7319216088Sken warn("%s: error allocating periph " 7320216088Sken "list", __func__); 7321216088Sken retval = 1; 7322216088Sken goto bailout; 7323216088Sken } 7324216088Sken bcopy(periph_result, &item->periph_matches[ 7325216088Sken item->num_periphs - 1], 7326216088Sken sizeof(*periph_result)); 7327216088Sken break; 7328216088Sken } 7329216088Sken default: 7330216088Sken fprintf(stderr, "%s: unexpected match " 7331216088Sken "type %d\n", __func__, 7332216088Sken ccb.cdm.matches[i].type); 7333216088Sken retval = 1; 7334216088Sken goto bailout; 7335216088Sken break; /*NOTREACHED*/ 7336216088Sken } 7337216088Sken } 7338216088Sken } while ((ccb.ccb_h.status == CAM_REQ_CMP) 7339216088Sken && (ccb.cdm.status == CAM_DEV_MATCH_MORE)); 7340216088Skenbailout: 7341216088Sken 7342216088Sken if (fd != -1) 7343216088Sken close(fd); 7344216088Sken 7345216088Sken free(patterns); 7346216088Sken 7347216088Sken free(ccb.cdm.matches); 7348216088Sken 7349216088Sken if (retval != 0) 7350216088Sken freebusdevlist(devlist); 7351216088Sken 7352216088Sken return (retval); 7353216088Sken} 7354216088Sken 7355216088Skenstatic void 7356216088Skenfreebusdevlist(struct cam_devlist *devlist) 7357216088Sken{ 7358216088Sken struct cam_devitem *item, *item2; 7359216088Sken 7360216088Sken STAILQ_FOREACH_SAFE(item, &devlist->dev_queue, links, item2) { 7361216088Sken STAILQ_REMOVE(&devlist->dev_queue, item, cam_devitem, 7362216088Sken links); 7363216088Sken free(item->device_id); 7364216088Sken free(item->periph_matches); 7365216088Sken free(item); 7366216088Sken } 7367216088Sken} 7368216088Sken 7369216088Skenstatic struct cam_devitem * 7370216088Skenfindsasdevice(struct cam_devlist *devlist, uint64_t sasaddr) 7371216088Sken{ 7372216088Sken struct cam_devitem *item; 7373216088Sken 7374216088Sken STAILQ_FOREACH(item, &devlist->dev_queue, links) { 7375251664Smav struct scsi_vpd_id_descriptor *idd; 7376216088Sken 7377216088Sken /* 7378216088Sken * XXX KDM look for LUN IDs as well? 7379216088Sken */ 7380251664Smav idd = scsi_get_devid(item->device_id, 7381223081Sgibbs item->device_id_len, 7382223081Sgibbs scsi_devid_is_sas_target); 7383251664Smav if (idd == NULL) 7384216088Sken continue; 7385216088Sken 7386251664Smav if (scsi_8btou64(idd->identifier) == sasaddr) 7387216088Sken return (item); 7388216088Sken } 7389216088Sken 7390216088Sken return (NULL); 7391216088Sken} 7392216088Sken 7393216088Skenstatic int 7394216088Skensmpphylist(struct cam_device *device, int argc, char **argv, 7395216088Sken char *combinedopt, int retry_count, int timeout) 7396216088Sken{ 7397216088Sken struct smp_report_general_request *rgrequest = NULL; 7398216088Sken struct smp_report_general_response *rgresponse = NULL; 7399216088Sken struct smp_discover_request *disrequest = NULL; 7400216088Sken struct smp_discover_response *disresponse = NULL; 7401216088Sken struct cam_devlist devlist; 7402216088Sken union ccb *ccb; 7403216088Sken int long_response = 0; 7404216088Sken int num_phys = 0; 7405216088Sken int quiet = 0; 7406216088Sken int retval; 7407216088Sken int i, c; 7408216088Sken 7409216088Sken /* 7410216088Sken * Note that at the moment we don't support sending SMP CCBs to 7411216088Sken * devices that aren't probed by CAM. 7412216088Sken */ 7413216088Sken ccb = cam_getccb(device); 7414216088Sken if (ccb == NULL) { 7415216088Sken warnx("%s: error allocating CCB", __func__); 7416216088Sken return (1); 7417216088Sken } 7418216088Sken 7419216088Sken bzero(&(&ccb->ccb_h)[1], 7420216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 7421239468Spluknet STAILQ_INIT(&devlist.dev_queue); 7422216088Sken 7423216088Sken rgrequest = malloc(sizeof(*rgrequest)); 7424216088Sken if (rgrequest == NULL) { 7425216088Sken warn("%s: unable to allocate %zd bytes", __func__, 7426216088Sken sizeof(*rgrequest)); 7427216088Sken retval = 1; 7428216088Sken goto bailout; 7429216088Sken } 7430216088Sken 7431216088Sken rgresponse = malloc(sizeof(*rgresponse)); 7432216088Sken if (rgresponse == NULL) { 7433216088Sken warn("%s: unable to allocate %zd bytes", __func__, 7434216088Sken sizeof(*rgresponse)); 7435216088Sken retval = 1; 7436216088Sken goto bailout; 7437216088Sken } 7438216088Sken 7439216088Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 7440216088Sken switch (c) { 7441216088Sken case 'l': 7442216088Sken long_response = 1; 7443216088Sken break; 7444216088Sken case 'q': 7445216088Sken quiet = 1; 7446216088Sken break; 7447216088Sken default: 7448216088Sken break; 7449216088Sken } 7450216088Sken } 7451216088Sken 7452216088Sken smp_report_general(&ccb->smpio, 7453216088Sken retry_count, 7454216088Sken /*cbfcnp*/ NULL, 7455216088Sken rgrequest, 7456216088Sken /*request_len*/ sizeof(*rgrequest), 7457216088Sken (uint8_t *)rgresponse, 7458216088Sken /*response_len*/ sizeof(*rgresponse), 7459216088Sken /*long_response*/ long_response, 7460216088Sken timeout); 7461216088Sken 7462216088Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 7463216088Sken 7464216088Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 7465216088Sken || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 7466228602Sdim const char warnstr[] = "error sending command"; 7467216088Sken 7468216088Sken if (retval < 0) 7469216088Sken warn(warnstr); 7470216088Sken else 7471216088Sken warnx(warnstr); 7472216088Sken 7473216088Sken if (arglist & CAM_ARG_VERBOSE) { 7474216088Sken cam_error_print(device, ccb, CAM_ESF_ALL, 7475216088Sken CAM_EPF_ALL, stderr); 7476216088Sken } 7477216088Sken retval = 1; 7478216088Sken goto bailout; 7479216088Sken } 7480216088Sken 7481216088Sken num_phys = rgresponse->num_phys; 7482216088Sken 7483216088Sken if (num_phys == 0) { 7484216088Sken if (quiet == 0) 7485216088Sken fprintf(stdout, "%s: No Phys reported\n", __func__); 7486216088Sken retval = 1; 7487216088Sken goto bailout; 7488216088Sken } 7489216088Sken 7490216088Sken devlist.path_id = device->path_id; 7491216088Sken 7492216088Sken retval = buildbusdevlist(&devlist); 7493216088Sken if (retval != 0) 7494216088Sken goto bailout; 7495216088Sken 7496216088Sken if (quiet == 0) { 7497216088Sken fprintf(stdout, "%d PHYs:\n", num_phys); 7498216088Sken fprintf(stdout, "PHY Attached SAS Address\n"); 7499216088Sken } 7500216088Sken 7501216088Sken disrequest = malloc(sizeof(*disrequest)); 7502216088Sken if (disrequest == NULL) { 7503216088Sken warn("%s: unable to allocate %zd bytes", __func__, 7504216088Sken sizeof(*disrequest)); 7505216088Sken retval = 1; 7506216088Sken goto bailout; 7507216088Sken } 7508216088Sken 7509216088Sken disresponse = malloc(sizeof(*disresponse)); 7510216088Sken if (disresponse == NULL) { 7511216088Sken warn("%s: unable to allocate %zd bytes", __func__, 7512216088Sken sizeof(*disresponse)); 7513216088Sken retval = 1; 7514216088Sken goto bailout; 7515216088Sken } 7516216088Sken 7517216088Sken for (i = 0; i < num_phys; i++) { 7518216088Sken struct cam_devitem *item; 7519216088Sken struct device_match_result *dev_match; 7520216088Sken char vendor[16], product[48], revision[16]; 7521216088Sken char tmpstr[256]; 7522216088Sken int j; 7523216088Sken 7524216088Sken bzero(&(&ccb->ccb_h)[1], 7525216088Sken sizeof(union ccb) - sizeof(struct ccb_hdr)); 7526216088Sken 7527216088Sken ccb->ccb_h.status = CAM_REQ_INPROG; 7528216088Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 7529216088Sken 7530216088Sken smp_discover(&ccb->smpio, 7531216088Sken retry_count, 7532216088Sken /*cbfcnp*/ NULL, 7533216088Sken disrequest, 7534216088Sken sizeof(*disrequest), 7535216088Sken (uint8_t *)disresponse, 7536216088Sken sizeof(*disresponse), 7537216088Sken long_response, 7538216088Sken /*ignore_zone_group*/ 0, 7539216088Sken /*phy*/ i, 7540216088Sken timeout); 7541216088Sken 7542216088Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 7543216088Sken || (((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 7544216088Sken && (disresponse->function_result != SMP_FR_PHY_VACANT))) { 7545228602Sdim const char warnstr[] = "error sending command"; 7546216088Sken 7547216088Sken if (retval < 0) 7548216088Sken warn(warnstr); 7549216088Sken else 7550216088Sken warnx(warnstr); 7551216088Sken 7552216088Sken if (arglist & CAM_ARG_VERBOSE) { 7553216088Sken cam_error_print(device, ccb, CAM_ESF_ALL, 7554216088Sken CAM_EPF_ALL, stderr); 7555216088Sken } 7556216088Sken retval = 1; 7557216088Sken goto bailout; 7558216088Sken } 7559216088Sken 7560216088Sken if (disresponse->function_result == SMP_FR_PHY_VACANT) { 7561216088Sken if (quiet == 0) 7562216088Sken fprintf(stdout, "%3d <vacant>\n", i); 7563216088Sken continue; 7564216088Sken } 7565216088Sken 7566250662Sasomers if (disresponse->attached_device == SMP_DIS_AD_TYPE_NONE) { 7567250662Sasomers item = NULL; 7568250662Sasomers } else { 7569250662Sasomers item = findsasdevice(&devlist, 7570250662Sasomers scsi_8btou64(disresponse->attached_sas_address)); 7571250662Sasomers } 7572216088Sken 7573216088Sken if ((quiet == 0) 7574216088Sken || (item != NULL)) { 7575216088Sken fprintf(stdout, "%3d 0x%016jx", i, 7576216088Sken (uintmax_t)scsi_8btou64( 7577216088Sken disresponse->attached_sas_address)); 7578216088Sken if (item == NULL) { 7579216088Sken fprintf(stdout, "\n"); 7580216088Sken continue; 7581216088Sken } 7582216088Sken } else if (quiet != 0) 7583216088Sken continue; 7584216088Sken 7585216088Sken dev_match = &item->dev_match; 7586216088Sken 7587216088Sken if (dev_match->protocol == PROTO_SCSI) { 7588216088Sken cam_strvis(vendor, dev_match->inq_data.vendor, 7589216088Sken sizeof(dev_match->inq_data.vendor), 7590216088Sken sizeof(vendor)); 7591216088Sken cam_strvis(product, dev_match->inq_data.product, 7592216088Sken sizeof(dev_match->inq_data.product), 7593216088Sken sizeof(product)); 7594216088Sken cam_strvis(revision, dev_match->inq_data.revision, 7595216088Sken sizeof(dev_match->inq_data.revision), 7596216088Sken sizeof(revision)); 7597216088Sken sprintf(tmpstr, "<%s %s %s>", vendor, product, 7598216088Sken revision); 7599216088Sken } else if ((dev_match->protocol == PROTO_ATA) 7600216088Sken || (dev_match->protocol == PROTO_SATAPM)) { 7601216088Sken cam_strvis(product, dev_match->ident_data.model, 7602216088Sken sizeof(dev_match->ident_data.model), 7603216088Sken sizeof(product)); 7604216088Sken cam_strvis(revision, dev_match->ident_data.revision, 7605216088Sken sizeof(dev_match->ident_data.revision), 7606216088Sken sizeof(revision)); 7607216088Sken sprintf(tmpstr, "<%s %s>", product, revision); 7608216088Sken } else { 7609216088Sken sprintf(tmpstr, "<>"); 7610216088Sken } 7611216088Sken fprintf(stdout, " %-33s ", tmpstr); 7612216088Sken 7613216088Sken /* 7614216088Sken * If we have 0 periphs, that's a bug... 7615216088Sken */ 7616216088Sken if (item->num_periphs == 0) { 7617216088Sken fprintf(stdout, "\n"); 7618216088Sken continue; 7619216088Sken } 7620216088Sken 7621216088Sken fprintf(stdout, "("); 7622216088Sken for (j = 0; j < item->num_periphs; j++) { 7623216088Sken if (j > 0) 7624216088Sken fprintf(stdout, ","); 7625216088Sken 7626216088Sken fprintf(stdout, "%s%d", 7627216088Sken item->periph_matches[j].periph_name, 7628216088Sken item->periph_matches[j].unit_number); 7629216088Sken 7630216088Sken } 7631216088Sken fprintf(stdout, ")\n"); 7632216088Sken } 7633216088Skenbailout: 7634216088Sken if (ccb != NULL) 7635216088Sken cam_freeccb(ccb); 7636216088Sken 7637216088Sken free(rgrequest); 7638216088Sken 7639216088Sken free(rgresponse); 7640216088Sken 7641216088Sken free(disrequest); 7642216088Sken 7643216088Sken free(disresponse); 7644216088Sken 7645216088Sken freebusdevlist(&devlist); 7646216088Sken 7647216088Sken return (retval); 7648216088Sken} 7649216088Sken 7650216088Skenstatic int 7651199079Smavatapm(struct cam_device *device, int argc, char **argv, 7652199079Smav char *combinedopt, int retry_count, int timeout) 7653199079Smav{ 7654199079Smav union ccb *ccb; 7655199079Smav int retval = 0; 7656199079Smav int t = -1; 7657199101Smav int c; 7658199079Smav u_char cmd, sc; 7659199079Smav 7660199079Smav ccb = cam_getccb(device); 7661199079Smav 7662199079Smav if (ccb == NULL) { 7663199079Smav warnx("%s: error allocating ccb", __func__); 7664199079Smav return (1); 7665199079Smav } 7666199079Smav 7667199079Smav while ((c = getopt(argc, argv, combinedopt)) != -1) { 7668199079Smav switch (c) { 7669199079Smav case 't': 7670199079Smav t = atoi(optarg); 7671199079Smav break; 7672199079Smav default: 7673199079Smav break; 7674199079Smav } 7675199079Smav } 7676199079Smav if (strcmp(argv[1], "idle") == 0) { 7677199079Smav if (t == -1) 7678199079Smav cmd = ATA_IDLE_IMMEDIATE; 7679199079Smav else 7680199079Smav cmd = ATA_IDLE_CMD; 7681199079Smav } else if (strcmp(argv[1], "standby") == 0) { 7682199079Smav if (t == -1) 7683199079Smav cmd = ATA_STANDBY_IMMEDIATE; 7684199079Smav else 7685199079Smav cmd = ATA_STANDBY_CMD; 7686199079Smav } else { 7687199079Smav cmd = ATA_SLEEP; 7688199079Smav t = -1; 7689199079Smav } 7690214807Sbrucec 7691199079Smav if (t < 0) 7692199079Smav sc = 0; 7693199079Smav else if (t <= (240 * 5)) 7694214807Sbrucec sc = (t + 4) / 5; 7695214807Sbrucec else if (t <= (252 * 5)) 7696214781Sbrucec /* special encoding for 21 minutes */ 7697214781Sbrucec sc = 252; 7698199079Smav else if (t <= (11 * 30 * 60)) 7699214807Sbrucec sc = (t - 1) / (30 * 60) + 241; 7700199079Smav else 7701199079Smav sc = 253; 7702214781Sbrucec 7703199079Smav cam_fill_ataio(&ccb->ataio, 7704199079Smav retry_count, 7705199079Smav NULL, 7706199079Smav /*flags*/CAM_DIR_NONE, 7707199079Smav MSG_SIMPLE_Q_TAG, 7708199079Smav /*data_ptr*/NULL, 7709199079Smav /*dxfer_len*/0, 7710199079Smav timeout ? timeout : 30 * 1000); 7711199079Smav ata_28bit_cmd(&ccb->ataio, cmd, 0, 0, sc); 7712199079Smav 7713199079Smav /* Disable freezing the device queue */ 7714199079Smav ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 7715199079Smav 7716199079Smav if (arglist & CAM_ARG_ERR_RECOVER) 7717199079Smav ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 7718199079Smav 7719199079Smav if (cam_send_ccb(device, ccb) < 0) { 7720199079Smav warn("error sending command"); 7721199079Smav 7722199079Smav if (arglist & CAM_ARG_VERBOSE) 7723199079Smav cam_error_print(device, ccb, CAM_ESF_ALL, 7724199079Smav CAM_EPF_ALL, stderr); 7725199079Smav 7726199079Smav retval = 1; 7727199079Smav goto bailout; 7728199079Smav } 7729199079Smav 7730199079Smav if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 7731199079Smav cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); 7732199079Smav retval = 1; 7733199079Smav goto bailout; 7734199079Smav } 7735199079Smavbailout: 7736199079Smav cam_freeccb(ccb); 7737199079Smav return (retval); 7738199079Smav} 7739199079Smav 774089471Sjoerg#endif /* MINIMALISTIC */ 774160767Sken 7742214321Smavvoid 7743241737Sedusage(int printlong) 774439214Sgibbs{ 7745241737Sed 7746241737Sed fprintf(printlong ? stdout : stderr, 774746938Sken"usage: camcontrol <command> [device id][generic args][command args]\n" 774889521Sjoerg" camcontrol devlist [-v]\n" 774989471Sjoerg#ifndef MINIMALISTIC 775046938Sken" camcontrol periphlist [dev_id][-n dev_name] [-u unit]\n" 775146938Sken" camcontrol tur [dev_id][generic args]\n" 775246938Sken" camcontrol inquiry [dev_id][generic args] [-D] [-S] [-R]\n" 7753202694Smav" camcontrol identify [dev_id][generic args] [-v]\n" 7754161506Sken" camcontrol reportluns [dev_id][generic args] [-c] [-l] [-r report]\n" 7755172093Sken" camcontrol readcap [dev_id][generic args] [-b] [-h] [-H] [-N]\n" 7756172093Sken" [-q] [-s]\n" 775746938Sken" camcontrol start [dev_id][generic args]\n" 775846938Sken" camcontrol stop [dev_id][generic args]\n" 7759103033Smdodd" camcontrol load [dev_id][generic args]\n" 776046938Sken" camcontrol eject [dev_id][generic args]\n" 776189471Sjoerg#endif /* MINIMALISTIC */ 776289515Sken" camcontrol rescan <all | bus[:target:lun]>\n" 776389515Sken" camcontrol reset <all | bus[:target:lun]>\n" 776489471Sjoerg#ifndef MINIMALISTIC 776546938Sken" camcontrol defects [dev_id][generic args] <-f format> [-P][-G]\n" 776664382Skbyanc" camcontrol modepage [dev_id][generic args] <-m page | -l>\n" 776764382Skbyanc" [-P pagectl][-e | -b][-d]\n" 7768196831Smav" camcontrol cmd [dev_id][generic args]\n" 7769196831Smav" <-a cmd [args] | -c cmd [args]>\n" 7770207498Smav" [-d] [-f] [-i len fmt|-o len fmt [args]] [-r fmt]\n" 7771216088Sken" camcontrol smpcmd [dev_id][generic args]\n" 7772216088Sken" <-r len fmt [args]> <-R len fmt [args]>\n" 7773216088Sken" camcontrol smprg [dev_id][generic args][-l]\n" 7774216088Sken" camcontrol smppc [dev_id][generic args] <-p phy> [-l]\n" 7775216088Sken" [-o operation][-d name][-m rate][-M rate]\n" 7776216088Sken" [-T pp_timeout][-a enable|disable]\n" 7777216088Sken" [-A enable|disable][-s enable|disable]\n" 7778216088Sken" [-S enable|disable]\n" 7779216088Sken" camcontrol smpphylist [dev_id][generic args][-l][-q]\n" 7780216088Sken" camcontrol smpmaninfo [dev_id][generic args][-l]\n" 7781107966Snjl" camcontrol debug [-I][-P][-T][-S][-X][-c]\n" 7782107966Snjl" <all|bus[:target[:lun]]|off>\n" 778346938Sken" camcontrol tags [dev_id][generic args] [-N tags] [-q] [-v]\n" 778446938Sken" camcontrol negotiate [dev_id][generic args] [-a][-c]\n" 7785199821Smav" [-D <enable|disable>][-M mode][-O offset]\n" 7786199821Smav" [-q][-R syncrate][-v][-T <enable|disable>]\n" 778746938Sken" [-U][-W bus_width]\n" 7788144134Sken" camcontrol format [dev_id][generic args][-q][-r][-w][-y]\n" 7789255307Sbryanv" camcontrol sanitize [dev_id][generic args]\n" 7790255307Sbryanv" [-a overwrite|block|crypto|exitfailure]\n" 7791255307Sbryanv" [-c passes][-I][-P pattern][-q][-U][-r][-w]\n" 7792255307Sbryanv" [-y]\n" 7793199079Smav" camcontrol idle [dev_id][generic args][-t time]\n" 7794199079Smav" camcontrol standby [dev_id][generic args][-t time]\n" 7795199079Smav" camcontrol sleep [dev_id][generic args]\n" 7796227961Semaste" camcontrol fwdownload [dev_id][generic args] <-f fw_image> [-y][-s]\n" 7797249115Ssmh" camcontrol security [dev_id][generic args]\n" 7798249115Ssmh" <-d pwd | -e pwd | -f | -h pwd | -k pwd>\n" 7799249115Ssmh" [-l <high|maximum>] [-q] [-s pwd] [-T timeout]\n" 7800249115Ssmh" [-U <user|master>] [-y]\n" 7801249895Ssmh" camcontrol hpa [dev_id][generic args] [-f] [-l] [-P] [-p pwd]\n" 7802249895Ssmh" [-q] [-s max_sectors] [-U pwd] [-y]\n" 780389471Sjoerg#endif /* MINIMALISTIC */ 780446938Sken" camcontrol help\n"); 7805241737Sed if (!printlong) 780646938Sken return; 780789471Sjoerg#ifndef MINIMALISTIC 780861228Sken fprintf(stdout, 780939214Sgibbs"Specify one of the following options:\n" 781039214Sgibbs"devlist list all CAM devices\n" 781139214Sgibbs"periphlist list all CAM peripheral drivers attached to a device\n" 781239214Sgibbs"tur send a test unit ready to the named device\n" 781339214Sgibbs"inquiry send a SCSI inquiry command to the named device\n" 7814195534Sscottl"identify send a ATA identify command to the named device\n" 7815161506Sken"reportluns send a SCSI report luns command to the device\n" 7816172093Sken"readcap send a SCSI read capacity command to the device\n" 781739214Sgibbs"start send a Start Unit command to the device\n" 781839214Sgibbs"stop send a Stop Unit command to the device\n" 7819103033Smdodd"load send a Start Unit command to the device with the load bit set\n" 782039214Sgibbs"eject send a Stop Unit command to the device with the eject bit set\n" 782189515Sken"rescan rescan all busses, the given bus, or bus:target:lun\n" 782289515Sken"reset reset all busses, the given bus, or bus:target:lun\n" 782339214Sgibbs"defects read the defect list of the specified device\n" 782439214Sgibbs"modepage display or edit (-e) the given mode page\n" 7825216088Sken"cmd send the given SCSI command, may need -i or -o as well\n" 7826216088Sken"smpcmd send the given SMP command, requires -o and -i\n" 7827216088Sken"smprg send the SMP Report General command\n" 7828216088Sken"smppc send the SMP PHY Control command, requires -p\n" 7829216088Sken"smpphylist display phys attached to a SAS expander\n" 7830216088Sken"smpmaninfo send the SMP Report Manufacturer Info command\n" 783139214Sgibbs"debug turn debugging on/off for a bus, target, or lun, or all devices\n" 783246581Sken"tags report or set the number of transaction slots for a device\n" 783346581Sken"negotiate report or set device negotiation parameters\n" 783460767Sken"format send the SCSI FORMAT UNIT command to the named device\n" 7835255307Sbryanv"sanitize send the SCSI SANITIZE command to the named device\n" 7836199079Smav"idle send the ATA IDLE command to the named device\n" 7837199079Smav"standby send the ATA STANDBY command to the named device\n" 7838199079Smav"sleep send the ATA SLEEP command to the named device\n" 7839227961Semaste"fwdownload program firmware of the named device with the given image" 7840249115Ssmh"security report or send ATA security commands to the named device\n" 784146938Sken"help this message\n" 784246938Sken"Device Identifiers:\n" 784346938Sken"bus:target specify the bus and target, lun defaults to 0\n" 784446938Sken"bus:target:lun specify the bus, target and lun\n" 784546938Sken"deviceUNIT specify the device name, like \"da4\" or \"cd2\"\n" 784639214Sgibbs"Generic arguments:\n" 784739214Sgibbs"-v be verbose, print out sense information\n" 784839214Sgibbs"-t timeout command timeout in seconds, overrides default timeout\n" 784961233Sken"-n dev_name specify device name, e.g. \"da\", \"cd\"\n" 785061233Sken"-u unit specify unit number, e.g. \"0\", \"5\"\n" 785139214Sgibbs"-E have the kernel attempt to perform SCSI error recovery\n" 785239214Sgibbs"-C count specify the SCSI command retry count (needs -E to work)\n" 785339214Sgibbs"modepage arguments:\n" 785464468Skbyanc"-l list all available mode pages\n" 785546581Sken"-m page specify the mode page to view or edit\n" 785639214Sgibbs"-e edit the specified mode page\n" 785764382Skbyanc"-b force view to binary mode\n" 785846581Sken"-d disable block descriptors for mode sense\n" 785939214Sgibbs"-P pgctl page control field 0-3\n" 786039214Sgibbs"defects arguments:\n" 786139214Sgibbs"-f format specify defect list format (block, bfi or phys)\n" 786239214Sgibbs"-G get the grown defect list\n" 7863229778Suqs"-P get the permanent defect list\n" 786439214Sgibbs"inquiry arguments:\n" 786539214Sgibbs"-D get the standard inquiry data\n" 786639214Sgibbs"-S get the serial number\n" 786739214Sgibbs"-R get the transfer rate, etc.\n" 7868161506Sken"reportluns arguments:\n" 7869161506Sken"-c only report a count of available LUNs\n" 7870161506Sken"-l only print out luns, and not a count\n" 7871161506Sken"-r <reporttype> specify \"default\", \"wellknown\" or \"all\"\n" 7872172093Sken"readcap arguments\n" 7873172093Sken"-b only report the blocksize\n" 7874172093Sken"-h human readable device size, base 2\n" 7875172093Sken"-H human readable device size, base 10\n" 7876172093Sken"-N print the number of blocks instead of last block\n" 7877172093Sken"-q quiet, print numbers only\n" 7878172093Sken"-s only report the last block/device size\n" 787939214Sgibbs"cmd arguments:\n" 788039214Sgibbs"-c cdb [args] specify the SCSI CDB\n" 788139214Sgibbs"-i len fmt specify input data and input data format\n" 788239214Sgibbs"-o len fmt [args] specify output data and output data fmt\n" 7883216088Sken"smpcmd arguments:\n" 7884216088Sken"-r len fmt [args] specify the SMP command to be sent\n" 7885216088Sken"-R len fmt [args] specify SMP response format\n" 7886216088Sken"smprg arguments:\n" 7887216088Sken"-l specify the long response format\n" 7888216088Sken"smppc arguments:\n" 7889216088Sken"-p phy specify the PHY to operate on\n" 7890216088Sken"-l specify the long request/response format\n" 7891216088Sken"-o operation specify the phy control operation\n" 7892216088Sken"-d name set the attached device name\n" 7893216088Sken"-m rate set the minimum physical link rate\n" 7894216088Sken"-M rate set the maximum physical link rate\n" 7895216088Sken"-T pp_timeout set the partial pathway timeout value\n" 7896216088Sken"-a enable|disable enable or disable SATA slumber\n" 7897216088Sken"-A enable|disable enable or disable SATA partial phy power\n" 7898216088Sken"-s enable|disable enable or disable SAS slumber\n" 7899216088Sken"-S enable|disable enable or disable SAS partial phy power\n" 7900216088Sken"smpphylist arguments:\n" 7901216088Sken"-l specify the long response format\n" 7902216088Sken"-q only print phys with attached devices\n" 7903216088Sken"smpmaninfo arguments:\n" 7904216088Sken"-l specify the long response format\n" 790539214Sgibbs"debug arguments:\n" 790639214Sgibbs"-I CAM_DEBUG_INFO -- scsi commands, errors, data\n" 790739214Sgibbs"-T CAM_DEBUG_TRACE -- routine flow tracking\n" 790839903Sken"-S CAM_DEBUG_SUBTRACE -- internal routine command flow\n" 790946581Sken"-c CAM_DEBUG_CDB -- print out SCSI CDBs only\n" 791046581Sken"tags arguments:\n" 791146581Sken"-N tags specify the number of tags to use for this device\n" 791246581Sken"-q be quiet, don't report the number of tags\n" 791346581Sken"-v report a number of tag-related parameters\n" 791446581Sken"negotiate arguments:\n" 791546581Sken"-a send a test unit ready after negotiation\n" 791646581Sken"-c report/set current negotiation settings\n" 791746581Sken"-D <arg> \"enable\" or \"disable\" disconnection\n" 7918199821Smav"-M mode set ATA mode\n" 791946581Sken"-O offset set command delay offset\n" 792046581Sken"-q be quiet, don't report anything\n" 792146581Sken"-R syncrate synchronization rate in MHz\n" 792246581Sken"-T <arg> \"enable\" or \"disable\" tagged queueing\n" 792346581Sken"-U report/set user negotiation settings\n" 792446581Sken"-W bus_width set the bus width in bits (8, 16 or 32)\n" 792560767Sken"-v also print a Path Inquiry CCB for the controller\n" 792660767Sken"format arguments:\n" 792760767Sken"-q be quiet, don't print status messages\n" 7928144134Sken"-r run in report only mode\n" 792960767Sken"-w don't send immediate format command\n" 7930199079Smav"-y don't ask any questions\n" 7931255307Sbryanv"sanitize arguments:\n" 7932255307Sbryanv"-a operation operation mode: overwrite, block, crypto or exitfailure\n" 7933255307Sbryanv"-c passes overwrite passes to perform (1 to 31)\n" 7934255307Sbryanv"-I invert overwrite pattern after each pass\n" 7935255307Sbryanv"-P pattern path to overwrite pattern file\n" 7936255307Sbryanv"-q be quiet, don't print status messages\n" 7937255307Sbryanv"-r run in report only mode\n" 7938255307Sbryanv"-U run operation in unrestricted completion exit mode\n" 7939255307Sbryanv"-w don't send immediate sanitize command\n" 7940255307Sbryanv"-y don't ask any questions\n" 7941199079Smav"idle/standby arguments:\n" 7942227961Semaste"-t <arg> number of seconds before respective state.\n" 7943227961Semaste"fwdownload arguments:\n" 7944227961Semaste"-f fw_image path to firmware image file\n" 7945227961Semaste"-y don't ask any questions\n" 7946227961Semaste"-s run in simulation mode\n" 7947249115Ssmh"-v print info for every firmware segment sent to device\n" 7948249115Ssmh"security arguments:\n" 7949249115Ssmh"-d pwd disable security using the given password for the selected\n" 7950249115Ssmh" user\n" 7951249115Ssmh"-e pwd erase the device using the given pwd for the selected user\n" 7952249115Ssmh"-f freeze the security configuration of the specified device\n" 7953249115Ssmh"-h pwd enhanced erase the device using the given pwd for the\n" 7954249115Ssmh" selected user\n" 7955249115Ssmh"-k pwd unlock the device using the given pwd for the selected\n" 7956249115Ssmh" user\n" 7957249115Ssmh"-l <high|maximum> specifies which security level to set: high or maximum\n" 7958249115Ssmh"-q be quiet, do not print any status messages\n" 7959249115Ssmh"-s pwd password the device (enable security) using the given\n" 7960249115Ssmh" pwd for the selected user\n" 7961249115Ssmh"-T timeout overrides the timeout (seconds) used for erase operation\n" 7962249115Ssmh"-U <user|master> specifies which user to set: user or master\n" 7963249115Ssmh"-y don't ask any questions\n" 7964249895Ssmh"hpa arguments:\n" 7965249895Ssmh"-f freeze the HPA configuration of the device\n" 7966249895Ssmh"-l lock the HPA configuration of the device\n" 7967249895Ssmh"-P make the HPA max sectors persist\n" 7968249895Ssmh"-p pwd Set the HPA configuration password required for unlock\n" 7969249895Ssmh" calls\n" 7970249895Ssmh"-q be quiet, do not print any status messages\n" 7971249895Ssmh"-s sectors configures the maximum user accessible sectors of the\n" 7972249895Ssmh" device\n" 7973249895Ssmh"-U pwd unlock the HPA configuration of the device\n" 7974249895Ssmh"-y don't ask any questions\n" 7975249115Ssmh); 797689471Sjoerg#endif /* MINIMALISTIC */ 797739214Sgibbs} 797839214Sgibbs 7979214321Smavint 798039214Sgibbsmain(int argc, char **argv) 798139214Sgibbs{ 798239214Sgibbs int c; 798339214Sgibbs char *device = NULL; 798439214Sgibbs int unit = 0; 798539214Sgibbs struct cam_device *cam_dev = NULL; 798639214Sgibbs int timeout = 0, retry_count = 1; 798739214Sgibbs camcontrol_optret optreturn; 798839214Sgibbs char *tstr; 7989118478Sjohan const char *mainopt = "C:En:t:u:v"; 7990118478Sjohan const char *subopt = NULL; 799139214Sgibbs char combinedopt[256]; 799246938Sken int error = 0, optstart = 2; 799346938Sken int devopen = 1; 7994118478Sjohan#ifndef MINIMALISTIC 7995260509Smav path_id_t bus; 7996260509Smav target_id_t target; 7997260509Smav lun_id_t lun; 7998118478Sjohan#endif /* MINIMALISTIC */ 799939214Sgibbs 8000103092Smdodd cmdlist = CAM_CMD_NONE; 800139214Sgibbs arglist = CAM_ARG_NONE; 800239214Sgibbs 800339214Sgibbs if (argc < 2) { 800446938Sken usage(0); 800539214Sgibbs exit(1); 800639214Sgibbs } 800739214Sgibbs 800839214Sgibbs /* 800939214Sgibbs * Get the base option. 801039214Sgibbs */ 8011216088Sken optreturn = getoption(option_table,argv[1], &cmdlist, &arglist,&subopt); 801239214Sgibbs 801339214Sgibbs if (optreturn == CC_OR_AMBIGUOUS) { 801439214Sgibbs warnx("ambiguous option %s", argv[1]); 801546938Sken usage(0); 801639214Sgibbs exit(1); 801739214Sgibbs } else if (optreturn == CC_OR_NOT_FOUND) { 801839214Sgibbs warnx("option %s not found", argv[1]); 801946938Sken usage(0); 802039214Sgibbs exit(1); 802139214Sgibbs } 802239214Sgibbs 802339214Sgibbs /* 802439214Sgibbs * Ahh, getopt(3) is a pain. 802539214Sgibbs * 802639214Sgibbs * This is a gross hack. There really aren't many other good 802739214Sgibbs * options (excuse the pun) for parsing options in a situation like 802839214Sgibbs * this. getopt is kinda braindead, so you end up having to run 802939214Sgibbs * through the options twice, and give each invocation of getopt 803039214Sgibbs * the option string for the other invocation. 8031214321Smav * 803239214Sgibbs * You would think that you could just have two groups of options. 803339214Sgibbs * The first group would get parsed by the first invocation of 803439214Sgibbs * getopt, and the second group would get parsed by the second 803539214Sgibbs * invocation of getopt. It doesn't quite work out that way. When 803639214Sgibbs * the first invocation of getopt finishes, it leaves optind pointing 803739214Sgibbs * to the argument _after_ the first argument in the second group. 803839214Sgibbs * So when the second invocation of getopt comes around, it doesn't 803939214Sgibbs * recognize the first argument it gets and then bails out. 8040214321Smav * 804139214Sgibbs * A nice alternative would be to have a flag for getopt that says 804239214Sgibbs * "just keep parsing arguments even when you encounter an unknown 804339214Sgibbs * argument", but there isn't one. So there's no real clean way to 804439214Sgibbs * easily parse two sets of arguments without having one invocation 804539214Sgibbs * of getopt know about the other. 8046214321Smav * 804739214Sgibbs * Without this hack, the first invocation of getopt would work as 804839214Sgibbs * long as the generic arguments are first, but the second invocation 804939214Sgibbs * (in the subfunction) would fail in one of two ways. In the case 805039214Sgibbs * where you don't set optreset, it would fail because optind may be 805139214Sgibbs * pointing to the argument after the one it should be pointing at. 805239214Sgibbs * In the case where you do set optreset, and reset optind, it would 805339214Sgibbs * fail because getopt would run into the first set of options, which 805439214Sgibbs * it doesn't understand. 805539214Sgibbs * 805639214Sgibbs * All of this would "sort of" work if you could somehow figure out 805739214Sgibbs * whether optind had been incremented one option too far. The 805839214Sgibbs * mechanics of that, however, are more daunting than just giving 805939214Sgibbs * both invocations all of the expect options for either invocation. 8060214321Smav * 806139214Sgibbs * Needless to say, I wouldn't mind if someone invented a better 806239214Sgibbs * (non-GPL!) command line parsing interface than getopt. I 806339214Sgibbs * wouldn't mind if someone added more knobs to getopt to make it 806439214Sgibbs * work better. Who knows, I may talk myself into doing it someday, 806539214Sgibbs * if the standards weenies let me. As it is, it just leads to 806639214Sgibbs * hackery like this and causes people to avoid it in some cases. 8067214321Smav * 806839214Sgibbs * KDM, September 8th, 1998 806939214Sgibbs */ 807039214Sgibbs if (subopt != NULL) 807139214Sgibbs sprintf(combinedopt, "%s%s", mainopt, subopt); 807239214Sgibbs else 807339214Sgibbs sprintf(combinedopt, "%s", mainopt); 807439214Sgibbs 807539214Sgibbs /* 807646938Sken * For these options we do not parse optional device arguments and 807746938Sken * we do not open a passthrough device. 807839214Sgibbs */ 8079103092Smdodd if ((cmdlist == CAM_CMD_RESCAN) 8080103092Smdodd || (cmdlist == CAM_CMD_RESET) 8081103092Smdodd || (cmdlist == CAM_CMD_DEVTREE) 8082103092Smdodd || (cmdlist == CAM_CMD_USAGE) 8083103092Smdodd || (cmdlist == CAM_CMD_DEBUG)) 808446938Sken devopen = 0; 808539214Sgibbs 808689471Sjoerg#ifndef MINIMALISTIC 808746938Sken if ((devopen == 1) 808846938Sken && (argc > 2 && argv[2][0] != '-')) { 808946938Sken char name[30]; 809046938Sken int rv; 809146938Sken 8092214073Sbrucec if (isdigit(argv[2][0])) { 809346938Sken /* device specified as bus:target[:lun] */ 809446938Sken rv = parse_btl(argv[2], &bus, &target, &lun, &arglist); 809546938Sken if (rv < 2) 809646938Sken errx(1, "numeric device specification must " 809746938Sken "be either bus:target, or " 809846938Sken "bus:target:lun"); 8099126514Sken /* default to 0 if lun was not specified */ 8100126514Sken if ((arglist & CAM_ARG_LUN) == 0) { 8101126514Sken lun = 0; 8102126514Sken arglist |= CAM_ARG_LUN; 8103126514Sken } 810446938Sken optstart++; 810546938Sken } else { 810646938Sken if (cam_get_device(argv[2], name, sizeof name, &unit) 810746938Sken == -1) 810846938Sken errx(1, "%s", cam_errbuf); 810946938Sken device = strdup(name); 811046938Sken arglist |= CAM_ARG_DEVICE | CAM_ARG_UNIT; 811146938Sken optstart++; 811246938Sken } 811346938Sken } 811489471Sjoerg#endif /* MINIMALISTIC */ 811539214Sgibbs /* 811646938Sken * Start getopt processing at argv[2/3], since we've already 811746938Sken * accepted argv[1..2] as the command name, and as a possible 811846938Sken * device name. 811946938Sken */ 812046938Sken optind = optstart; 812146938Sken 812246938Sken /* 812339214Sgibbs * Now we run through the argument list looking for generic 812439214Sgibbs * options, and ignoring options that possibly belong to 812539214Sgibbs * subfunctions. 812639214Sgibbs */ 812739214Sgibbs while ((c = getopt(argc, argv, combinedopt))!= -1){ 812839214Sgibbs switch(c) { 812939214Sgibbs case 'C': 813039214Sgibbs retry_count = strtol(optarg, NULL, 0); 813139214Sgibbs if (retry_count < 0) 813239214Sgibbs errx(1, "retry count %d is < 0", 813339214Sgibbs retry_count); 813439214Sgibbs arglist |= CAM_ARG_RETRIES; 813539214Sgibbs break; 813639214Sgibbs case 'E': 813739214Sgibbs arglist |= CAM_ARG_ERR_RECOVER; 813839214Sgibbs break; 813939214Sgibbs case 'n': 814039214Sgibbs arglist |= CAM_ARG_DEVICE; 814139214Sgibbs tstr = optarg; 814239214Sgibbs while (isspace(*tstr) && (*tstr != '\0')) 814339214Sgibbs tstr++; 814439214Sgibbs device = (char *)strdup(tstr); 814539214Sgibbs break; 814639214Sgibbs case 't': 814739214Sgibbs timeout = strtol(optarg, NULL, 0); 814839214Sgibbs if (timeout < 0) 814939214Sgibbs errx(1, "invalid timeout %d", timeout); 815039214Sgibbs /* Convert the timeout from seconds to ms */ 815139214Sgibbs timeout *= 1000; 815239214Sgibbs arglist |= CAM_ARG_TIMEOUT; 815339214Sgibbs break; 815439214Sgibbs case 'u': 815539214Sgibbs arglist |= CAM_ARG_UNIT; 815639214Sgibbs unit = strtol(optarg, NULL, 0); 815739214Sgibbs break; 815839214Sgibbs case 'v': 815939214Sgibbs arglist |= CAM_ARG_VERBOSE; 816039214Sgibbs break; 816139214Sgibbs default: 816239214Sgibbs break; 816339214Sgibbs } 816439214Sgibbs } 816539214Sgibbs 816689471Sjoerg#ifndef MINIMALISTIC 816739214Sgibbs /* 816839214Sgibbs * For most commands we'll want to open the passthrough device 816939214Sgibbs * associated with the specified device. In the case of the rescan 817039214Sgibbs * commands, we don't use a passthrough device at all, just the 817139214Sgibbs * transport layer device. 817239214Sgibbs */ 817346938Sken if (devopen == 1) { 817461233Sken if (((arglist & (CAM_ARG_BUS|CAM_ARG_TARGET)) == 0) 817561233Sken && (((arglist & CAM_ARG_DEVICE) == 0) 817661233Sken || ((arglist & CAM_ARG_UNIT) == 0))) { 817761233Sken errx(1, "subcommand \"%s\" requires a valid device " 817861233Sken "identifier", argv[1]); 817961233Sken } 818061233Sken 818146938Sken if ((cam_dev = ((arglist & (CAM_ARG_BUS | CAM_ARG_TARGET))? 818246938Sken cam_open_btl(bus, target, lun, O_RDWR, NULL) : 818346938Sken cam_open_spec_device(device,unit,O_RDWR,NULL))) 818446938Sken == NULL) 818539214Sgibbs errx(1,"%s", cam_errbuf); 818639214Sgibbs } 818789471Sjoerg#endif /* MINIMALISTIC */ 818839214Sgibbs 818939214Sgibbs /* 819041112Sken * Reset optind to 2, and reset getopt, so these routines can parse 819139214Sgibbs * the arguments again. 819239214Sgibbs */ 819346938Sken optind = optstart; 819439214Sgibbs optreset = 1; 819539214Sgibbs 8196103092Smdodd switch(cmdlist) { 819789471Sjoerg#ifndef MINIMALISTIC 8198103092Smdodd case CAM_CMD_DEVLIST: 819939214Sgibbs error = getdevlist(cam_dev); 820039214Sgibbs break; 8201249895Ssmh case CAM_CMD_HPA: 8202249895Ssmh error = atahpa(cam_dev, retry_count, timeout, 8203249895Ssmh argc, argv, combinedopt); 8204249895Ssmh break; 820589521Sjoerg#endif /* MINIMALISTIC */ 8206103092Smdodd case CAM_CMD_DEVTREE: 8207260059Sscottl error = getdevtree(argc, argv, combinedopt); 820839214Sgibbs break; 820989521Sjoerg#ifndef MINIMALISTIC 8210103092Smdodd case CAM_CMD_TUR: 821146581Sken error = testunitready(cam_dev, retry_count, timeout, 0); 821239214Sgibbs break; 8213103092Smdodd case CAM_CMD_INQUIRY: 821439214Sgibbs error = scsidoinquiry(cam_dev, argc, argv, combinedopt, 821539214Sgibbs retry_count, timeout); 821639214Sgibbs break; 8217195534Sscottl case CAM_CMD_IDENTIFY: 8218195534Sscottl error = ataidentify(cam_dev, retry_count, timeout); 8219195534Sscottl break; 8220103092Smdodd case CAM_CMD_STARTSTOP: 822139214Sgibbs error = scsistart(cam_dev, arglist & CAM_ARG_START_UNIT, 822239214Sgibbs arglist & CAM_ARG_EJECT, retry_count, 822339214Sgibbs timeout); 822439214Sgibbs break; 822589471Sjoerg#endif /* MINIMALISTIC */ 8226103092Smdodd case CAM_CMD_RESCAN: 822741962Smjacob error = dorescan_or_reset(argc, argv, 1); 822839214Sgibbs break; 8229103092Smdodd case CAM_CMD_RESET: 823041962Smjacob error = dorescan_or_reset(argc, argv, 0); 823141962Smjacob break; 823289471Sjoerg#ifndef MINIMALISTIC 8233103092Smdodd case CAM_CMD_READ_DEFECTS: 823439214Sgibbs error = readdefects(cam_dev, argc, argv, combinedopt, 823539214Sgibbs retry_count, timeout); 823639214Sgibbs break; 8237103092Smdodd case CAM_CMD_MODE_PAGE: 823839214Sgibbs modepage(cam_dev, argc, argv, combinedopt, 823939214Sgibbs retry_count, timeout); 824039214Sgibbs break; 8241103092Smdodd case CAM_CMD_SCSI_CMD: 824239214Sgibbs error = scsicmd(cam_dev, argc, argv, combinedopt, 824339214Sgibbs retry_count, timeout); 824439214Sgibbs break; 8245216088Sken case CAM_CMD_SMP_CMD: 8246216088Sken error = smpcmd(cam_dev, argc, argv, combinedopt, 8247216088Sken retry_count, timeout); 8248216088Sken break; 8249216088Sken case CAM_CMD_SMP_RG: 8250216088Sken error = smpreportgeneral(cam_dev, argc, argv, 8251216088Sken combinedopt, retry_count, 8252216088Sken timeout); 8253216088Sken break; 8254216088Sken case CAM_CMD_SMP_PC: 8255216088Sken error = smpphycontrol(cam_dev, argc, argv, combinedopt, 8256216088Sken retry_count, timeout); 8257216088Sken break; 8258216088Sken case CAM_CMD_SMP_PHYLIST: 8259216088Sken error = smpphylist(cam_dev, argc, argv, combinedopt, 8260216088Sken retry_count, timeout); 8261216088Sken break; 8262216088Sken case CAM_CMD_SMP_MANINFO: 8263216088Sken error = smpmaninfo(cam_dev, argc, argv, combinedopt, 8264216088Sken retry_count, timeout); 8265216088Sken break; 8266103092Smdodd case CAM_CMD_DEBUG: 826739214Sgibbs error = camdebug(argc, argv, combinedopt); 826839214Sgibbs break; 8269103092Smdodd case CAM_CMD_TAG: 827046581Sken error = tagcontrol(cam_dev, argc, argv, combinedopt); 827146581Sken break; 8272103092Smdodd case CAM_CMD_RATE: 827346581Sken error = ratecontrol(cam_dev, retry_count, timeout, 827446581Sken argc, argv, combinedopt); 827546581Sken break; 8276103092Smdodd case CAM_CMD_FORMAT: 827760767Sken error = scsiformat(cam_dev, argc, argv, 827860767Sken combinedopt, retry_count, timeout); 827960767Sken break; 8280161506Sken case CAM_CMD_REPORTLUNS: 8281161506Sken error = scsireportluns(cam_dev, argc, argv, 8282161506Sken combinedopt, retry_count, 8283161506Sken timeout); 8284161506Sken break; 8285172093Sken case CAM_CMD_READCAP: 8286172093Sken error = scsireadcapacity(cam_dev, argc, argv, 8287172093Sken combinedopt, retry_count, 8288172093Sken timeout); 8289172093Sken break; 8290199079Smav case CAM_CMD_IDLE: 8291199079Smav case CAM_CMD_STANDBY: 8292199079Smav case CAM_CMD_SLEEP: 8293199079Smav error = atapm(cam_dev, argc, argv, 8294249115Ssmh combinedopt, retry_count, timeout); 8295199079Smav break; 8296249115Ssmh case CAM_CMD_SECURITY: 8297249115Ssmh error = atasecurity(cam_dev, retry_count, timeout, 8298249115Ssmh argc, argv, combinedopt); 8299249115Ssmh break; 8300227961Semaste case CAM_CMD_DOWNLOAD_FW: 8301227961Semaste error = fwdownload(cam_dev, argc, argv, combinedopt, 8302237281Sscottl arglist & CAM_ARG_VERBOSE, retry_count, timeout, 8303237281Sscottl get_disk_type(cam_dev)); 8304227961Semaste break; 8305255307Sbryanv case CAM_CMD_SANITIZE: 8306255307Sbryanv error = scsisanitize(cam_dev, argc, argv, 8307255307Sbryanv combinedopt, retry_count, timeout); 8308255307Sbryanv break; 830989471Sjoerg#endif /* MINIMALISTIC */ 8310103092Smdodd case CAM_CMD_USAGE: 831146938Sken usage(1); 831246938Sken break; 831339214Sgibbs default: 831446938Sken usage(0); 831539214Sgibbs error = 1; 831639214Sgibbs break; 831739214Sgibbs } 831839214Sgibbs 831939214Sgibbs if (cam_dev != NULL) 832039214Sgibbs cam_close_device(cam_dev); 832139214Sgibbs 832239214Sgibbs exit(error); 832339214Sgibbs} 8324