camcontrol.c revision 215507
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 215507 2010-11-19 03:47:10Z rstone $"); 31114513Sobrien 3239214Sgibbs#include <sys/ioctl.h> 33111195Sjohan#include <sys/stdint.h> 3439214Sgibbs#include <sys/types.h> 35195534Sscottl#include <sys/endian.h> 36111195Sjohan 3739214Sgibbs#include <stdio.h> 3839214Sgibbs#include <stdlib.h> 3939214Sgibbs#include <string.h> 4039214Sgibbs#include <unistd.h> 4139214Sgibbs#include <fcntl.h> 4239214Sgibbs#include <ctype.h> 4339214Sgibbs#include <err.h> 44172093Sken#include <libutil.h> 4539214Sgibbs 4639214Sgibbs#include <cam/cam.h> 4739214Sgibbs#include <cam/cam_debug.h> 4839214Sgibbs#include <cam/cam_ccb.h> 4939214Sgibbs#include <cam/scsi/scsi_all.h> 5039214Sgibbs#include <cam/scsi/scsi_da.h> 5139214Sgibbs#include <cam/scsi/scsi_pass.h> 5239214Sgibbs#include <cam/scsi/scsi_message.h> 53195534Sscottl#include <cam/ata/ata_all.h> 5439214Sgibbs#include <camlib.h> 5539214Sgibbs#include "camcontrol.h" 5639214Sgibbs 5739214Sgibbstypedef enum { 58103092Smdodd CAM_CMD_NONE = 0x00000000, 59103092Smdodd CAM_CMD_DEVLIST = 0x00000001, 60103092Smdodd CAM_CMD_TUR = 0x00000002, 61103092Smdodd CAM_CMD_INQUIRY = 0x00000003, 62103092Smdodd CAM_CMD_STARTSTOP = 0x00000004, 63103092Smdodd CAM_CMD_RESCAN = 0x00000005, 64103092Smdodd CAM_CMD_READ_DEFECTS = 0x00000006, 65103092Smdodd CAM_CMD_MODE_PAGE = 0x00000007, 66103092Smdodd CAM_CMD_SCSI_CMD = 0x00000008, 67103092Smdodd CAM_CMD_DEVTREE = 0x00000009, 68103092Smdodd CAM_CMD_USAGE = 0x0000000a, 69103092Smdodd CAM_CMD_DEBUG = 0x0000000b, 70103092Smdodd CAM_CMD_RESET = 0x0000000c, 71103092Smdodd CAM_CMD_FORMAT = 0x0000000d, 72103092Smdodd CAM_CMD_TAG = 0x0000000e, 73103092Smdodd CAM_CMD_RATE = 0x0000000f, 74103092Smdodd CAM_CMD_DETACH = 0x00000010, 75172093Sken CAM_CMD_REPORTLUNS = 0x00000011, 76195534Sscottl CAM_CMD_READCAP = 0x00000012, 77199079Smav CAM_CMD_IDENTIFY = 0x00000013, 78199079Smav CAM_CMD_IDLE = 0x00000014, 79199079Smav CAM_CMD_STANDBY = 0x00000015, 80199079Smav CAM_CMD_SLEEP = 0x00000016 81103092Smdodd} cam_cmdmask; 82103092Smdodd 83103092Smdoddtypedef enum { 8439214Sgibbs CAM_ARG_NONE = 0x00000000, 85103092Smdodd CAM_ARG_VERBOSE = 0x00000001, 86103092Smdodd CAM_ARG_DEVICE = 0x00000002, 87103092Smdodd CAM_ARG_BUS = 0x00000004, 88103092Smdodd CAM_ARG_TARGET = 0x00000008, 89103092Smdodd CAM_ARG_LUN = 0x00000010, 90103092Smdodd CAM_ARG_EJECT = 0x00000020, 91103092Smdodd CAM_ARG_UNIT = 0x00000040, 92103092Smdodd CAM_ARG_FORMAT_BLOCK = 0x00000080, 93103092Smdodd CAM_ARG_FORMAT_BFI = 0x00000100, 94103092Smdodd CAM_ARG_FORMAT_PHYS = 0x00000200, 95103092Smdodd CAM_ARG_PLIST = 0x00000400, 96103092Smdodd CAM_ARG_GLIST = 0x00000800, 97103092Smdodd CAM_ARG_GET_SERIAL = 0x00001000, 98103092Smdodd CAM_ARG_GET_STDINQ = 0x00002000, 99103092Smdodd CAM_ARG_GET_XFERRATE = 0x00004000, 100103092Smdodd CAM_ARG_INQ_MASK = 0x00007000, 101103092Smdodd CAM_ARG_MODE_EDIT = 0x00008000, 102103092Smdodd CAM_ARG_PAGE_CNTL = 0x00010000, 103103092Smdodd CAM_ARG_TIMEOUT = 0x00020000, 104103092Smdodd CAM_ARG_CMD_IN = 0x00040000, 105103092Smdodd CAM_ARG_CMD_OUT = 0x00080000, 106103092Smdodd CAM_ARG_DBD = 0x00100000, 107103092Smdodd CAM_ARG_ERR_RECOVER = 0x00200000, 108103092Smdodd CAM_ARG_RETRIES = 0x00400000, 109103092Smdodd CAM_ARG_START_UNIT = 0x00800000, 110103092Smdodd CAM_ARG_DEBUG_INFO = 0x01000000, 111103092Smdodd CAM_ARG_DEBUG_TRACE = 0x02000000, 112103092Smdodd CAM_ARG_DEBUG_SUBTRACE = 0x04000000, 113103092Smdodd CAM_ARG_DEBUG_CDB = 0x08000000, 114107966Snjl CAM_ARG_DEBUG_XPT = 0x10000000, 115107966Snjl CAM_ARG_DEBUG_PERIPH = 0x20000000, 11639214Sgibbs} cam_argmask; 11739214Sgibbs 11839214Sgibbsstruct camcontrol_opts { 119214321Smav const char *optname; 120103092Smdodd cam_cmdmask cmdnum; 12139214Sgibbs cam_argmask argnum; 12239214Sgibbs const char *subopt; 12339214Sgibbs}; 12439214Sgibbs 12589471Sjoerg#ifndef MINIMALISTIC 126207498Smavstatic const char scsicmd_opts[] = "a:c:dfi:o:r"; 12739214Sgibbsstatic const char readdefect_opts[] = "f:GP"; 128199821Smavstatic const char negotiate_opts[] = "acD:M:O:qR:T:UW:"; 12989471Sjoerg#endif 13039214Sgibbs 13139214Sgibbsstruct camcontrol_opts option_table[] = { 13289471Sjoerg#ifndef MINIMALISTIC 133103092Smdodd {"tur", CAM_CMD_TUR, CAM_ARG_NONE, NULL}, 134103092Smdodd {"inquiry", CAM_CMD_INQUIRY, CAM_ARG_NONE, "DSR"}, 135195534Sscottl {"identify", CAM_CMD_IDENTIFY, CAM_ARG_NONE, NULL}, 136103092Smdodd {"start", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT, NULL}, 137103092Smdodd {"stop", CAM_CMD_STARTSTOP, CAM_ARG_NONE, NULL}, 138103092Smdodd {"load", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT | CAM_ARG_EJECT, NULL}, 139103092Smdodd {"eject", CAM_CMD_STARTSTOP, CAM_ARG_EJECT, NULL}, 140161506Sken {"reportluns", CAM_CMD_REPORTLUNS, CAM_ARG_NONE, "clr:"}, 141172093Sken {"readcapacity", CAM_CMD_READCAP, CAM_ARG_NONE, "bhHNqs"}, 14289471Sjoerg#endif /* MINIMALISTIC */ 143103092Smdodd {"rescan", CAM_CMD_RESCAN, CAM_ARG_NONE, NULL}, 144103092Smdodd {"reset", CAM_CMD_RESET, CAM_ARG_NONE, NULL}, 14589471Sjoerg#ifndef MINIMALISTIC 146103092Smdodd {"cmd", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts}, 147103092Smdodd {"command", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts}, 148103092Smdodd {"defects", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts}, 149103092Smdodd {"defectlist", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts}, 15089521Sjoerg#endif /* MINIMALISTIC */ 151103092Smdodd {"devlist", CAM_CMD_DEVTREE, CAM_ARG_NONE, NULL}, 15289521Sjoerg#ifndef MINIMALISTIC 153103092Smdodd {"periphlist", CAM_CMD_DEVLIST, CAM_ARG_NONE, NULL}, 154103092Smdodd {"modepage", CAM_CMD_MODE_PAGE, CAM_ARG_NONE, "bdelm:P:"}, 155103092Smdodd {"tags", CAM_CMD_TAG, CAM_ARG_NONE, "N:q"}, 156103092Smdodd {"negotiate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts}, 157103092Smdodd {"rate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts}, 158107966Snjl {"debug", CAM_CMD_DEBUG, CAM_ARG_NONE, "IPTSXc"}, 159144134Sken {"format", CAM_CMD_FORMAT, CAM_ARG_NONE, "qrwy"}, 160199079Smav {"idle", CAM_CMD_IDLE, CAM_ARG_NONE, "t:"}, 161199079Smav {"standby", CAM_CMD_STANDBY, CAM_ARG_NONE, "t:"}, 162199079Smav {"sleep", CAM_CMD_SLEEP, CAM_ARG_NONE, ""}, 16389471Sjoerg#endif /* MINIMALISTIC */ 164103092Smdodd {"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL}, 165103092Smdodd {"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL}, 166103092Smdodd {"-h", CAM_CMD_USAGE, CAM_ARG_NONE, NULL}, 167103092Smdodd {NULL, 0, 0, NULL} 16839214Sgibbs}; 16939214Sgibbs 17039214Sgibbstypedef enum { 17139214Sgibbs CC_OR_NOT_FOUND, 17239214Sgibbs CC_OR_AMBIGUOUS, 17339214Sgibbs CC_OR_FOUND 17439214Sgibbs} camcontrol_optret; 17539214Sgibbs 176103092Smdoddcam_cmdmask cmdlist; 17739214Sgibbscam_argmask arglist; 17839214Sgibbs 17939214Sgibbs 180103092Smdoddcamcontrol_optret getoption(char *arg, cam_cmdmask *cmdnum, cam_argmask *argnum, 181118478Sjohan const char **subopt); 18289471Sjoerg#ifndef MINIMALISTIC 18339214Sgibbsstatic int getdevlist(struct cam_device *device); 184126514Sken#endif /* MINIMALISTIC */ 18539214Sgibbsstatic int getdevtree(void); 186126514Sken#ifndef MINIMALISTIC 18739214Sgibbsstatic int testunitready(struct cam_device *device, int retry_count, 18846581Sken int timeout, int quiet); 18939214Sgibbsstatic int scsistart(struct cam_device *device, int startstop, int loadeject, 19039214Sgibbs int retry_count, int timeout); 19139214Sgibbsstatic int scsidoinquiry(struct cam_device *device, int argc, char **argv, 19239214Sgibbs char *combinedopt, int retry_count, int timeout); 19339214Sgibbsstatic int scsiinquiry(struct cam_device *device, int retry_count, int timeout); 19439214Sgibbsstatic int scsiserial(struct cam_device *device, int retry_count, int timeout); 195198709Smavstatic int camxferrate(struct cam_device *device); 19689471Sjoerg#endif /* MINIMALISTIC */ 19746938Skenstatic int parse_btl(char *tstr, int *bus, int *target, int *lun, 198118478Sjohan cam_argmask *arglst); 19941962Smjacobstatic int dorescan_or_reset(int argc, char **argv, int rescan); 20041962Smjacobstatic int rescan_or_reset_bus(int bus, int rescan); 20141962Smjacobstatic int scanlun_or_reset_dev(int bus, int target, int lun, int scan); 20289471Sjoerg#ifndef MINIMALISTIC 20339214Sgibbsstatic int readdefects(struct cam_device *device, int argc, char **argv, 20439214Sgibbs char *combinedopt, int retry_count, int timeout); 20539214Sgibbsstatic void modepage(struct cam_device *device, int argc, char **argv, 20639214Sgibbs char *combinedopt, int retry_count, int timeout); 207214321Smavstatic int scsicmd(struct cam_device *device, int argc, char **argv, 20839214Sgibbs char *combinedopt, int retry_count, int timeout); 20946581Skenstatic int tagcontrol(struct cam_device *device, int argc, char **argv, 21046581Sken char *combinedopt); 21146581Skenstatic void cts_print(struct cam_device *device, 21246581Sken struct ccb_trans_settings *cts); 21346581Skenstatic void cpi_print(struct ccb_pathinq *cpi); 21446581Skenstatic int get_cpi(struct cam_device *device, struct ccb_pathinq *cpi); 215196658Smavstatic int get_cgd(struct cam_device *device, struct ccb_getdev *cgd); 21646581Skenstatic int get_print_cts(struct cam_device *device, int user_settings, 21746581Sken int quiet, struct ccb_trans_settings *cts); 21846581Skenstatic int ratecontrol(struct cam_device *device, int retry_count, 21946581Sken int timeout, int argc, char **argv, char *combinedopt); 22060767Skenstatic int scsiformat(struct cam_device *device, int argc, char **argv, 22160767Sken char *combinedopt, int retry_count, int timeout); 222161506Skenstatic int scsireportluns(struct cam_device *device, int argc, char **argv, 223161506Sken char *combinedopt, int retry_count, int timeout); 224172093Skenstatic int scsireadcapacity(struct cam_device *device, int argc, char **argv, 225172093Sken char *combinedopt, int retry_count, int timeout); 226199079Smavstatic int atapm(struct cam_device *device, int argc, char **argv, 227199079Smav char *combinedopt, int retry_count, int timeout); 22889471Sjoerg#endif /* MINIMALISTIC */ 229199747Smav#ifndef min 230199747Smav#define min(a,b) (((a)<(b))?(a):(b)) 231199747Smav#endif 232199747Smav#ifndef max 233199747Smav#define max(a,b) (((a)>(b))?(a):(b)) 234199747Smav#endif 23539214Sgibbs 23639214Sgibbscamcontrol_optret 237214321Smavgetoption(char *arg, cam_cmdmask *cmdnum, cam_argmask *argnum, 238118478Sjohan const char **subopt) 23939214Sgibbs{ 24039214Sgibbs struct camcontrol_opts *opts; 24139214Sgibbs int num_matches = 0; 24239214Sgibbs 24339214Sgibbs for (opts = option_table; (opts != NULL) && (opts->optname != NULL); 24439214Sgibbs opts++) { 24539214Sgibbs if (strncmp(opts->optname, arg, strlen(arg)) == 0) { 246103092Smdodd *cmdnum = opts->cmdnum; 24739214Sgibbs *argnum = opts->argnum; 248118478Sjohan *subopt = opts->subopt; 24939214Sgibbs if (++num_matches > 1) 25039214Sgibbs return(CC_OR_AMBIGUOUS); 25139214Sgibbs } 25239214Sgibbs } 25339214Sgibbs 25439214Sgibbs if (num_matches > 0) 25539214Sgibbs return(CC_OR_FOUND); 25639214Sgibbs else 25739214Sgibbs return(CC_OR_NOT_FOUND); 25839214Sgibbs} 25939214Sgibbs 26089471Sjoerg#ifndef MINIMALISTIC 26139214Sgibbsstatic int 26239214Sgibbsgetdevlist(struct cam_device *device) 26339214Sgibbs{ 26439214Sgibbs union ccb *ccb; 26539214Sgibbs char status[32]; 26639214Sgibbs int error = 0; 26739214Sgibbs 26839214Sgibbs ccb = cam_getccb(device); 26939214Sgibbs 27039214Sgibbs ccb->ccb_h.func_code = XPT_GDEVLIST; 27139214Sgibbs ccb->ccb_h.flags = CAM_DIR_NONE; 27239214Sgibbs ccb->ccb_h.retry_count = 1; 27339214Sgibbs ccb->cgdl.index = 0; 27439214Sgibbs ccb->cgdl.status = CAM_GDEVLIST_MORE_DEVS; 27539214Sgibbs while (ccb->cgdl.status == CAM_GDEVLIST_MORE_DEVS) { 27639214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 27739214Sgibbs perror("error getting device list"); 27839214Sgibbs cam_freeccb(ccb); 27939214Sgibbs return(1); 28039214Sgibbs } 28139214Sgibbs 28239214Sgibbs status[0] = '\0'; 28339214Sgibbs 28439214Sgibbs switch (ccb->cgdl.status) { 28539214Sgibbs case CAM_GDEVLIST_MORE_DEVS: 28639214Sgibbs strcpy(status, "MORE"); 28739214Sgibbs break; 28839214Sgibbs case CAM_GDEVLIST_LAST_DEVICE: 28939214Sgibbs strcpy(status, "LAST"); 29039214Sgibbs break; 29139214Sgibbs case CAM_GDEVLIST_LIST_CHANGED: 29239214Sgibbs strcpy(status, "CHANGED"); 29339214Sgibbs break; 29439214Sgibbs case CAM_GDEVLIST_ERROR: 29539214Sgibbs strcpy(status, "ERROR"); 29639214Sgibbs error = 1; 29739214Sgibbs break; 29839214Sgibbs } 29939214Sgibbs 30039214Sgibbs fprintf(stdout, "%s%d: generation: %d index: %d status: %s\n", 30139214Sgibbs ccb->cgdl.periph_name, 30239214Sgibbs ccb->cgdl.unit_number, 30339214Sgibbs ccb->cgdl.generation, 30439214Sgibbs ccb->cgdl.index, 30539214Sgibbs status); 30639214Sgibbs 30739214Sgibbs /* 30839214Sgibbs * If the list has changed, we need to start over from the 30939214Sgibbs * beginning. 31039214Sgibbs */ 31139214Sgibbs if (ccb->cgdl.status == CAM_GDEVLIST_LIST_CHANGED) 31239214Sgibbs ccb->cgdl.index = 0; 31339214Sgibbs } 31439214Sgibbs 31539214Sgibbs cam_freeccb(ccb); 31639214Sgibbs 31739214Sgibbs return(error); 31839214Sgibbs} 31989521Sjoerg#endif /* MINIMALISTIC */ 32039214Sgibbs 32139214Sgibbsstatic int 32239214Sgibbsgetdevtree(void) 32339214Sgibbs{ 32439214Sgibbs union ccb ccb; 325102192Sjohan int bufsize, fd; 326102192Sjohan unsigned int i; 32739214Sgibbs int need_close = 0; 32839214Sgibbs int error = 0; 32946581Sken int skip_device = 0; 33039214Sgibbs 33139214Sgibbs if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) { 33239214Sgibbs warn("couldn't open %s", XPT_DEVICE); 33339214Sgibbs return(1); 33439214Sgibbs } 33539214Sgibbs 336126514Sken bzero(&ccb, sizeof(union ccb)); 33739214Sgibbs 338126514Sken ccb.ccb_h.path_id = CAM_XPT_PATH_ID; 339126514Sken ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; 340126514Sken ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; 341126514Sken 34239214Sgibbs ccb.ccb_h.func_code = XPT_DEV_MATCH; 34339214Sgibbs bufsize = sizeof(struct dev_match_result) * 100; 34439214Sgibbs ccb.cdm.match_buf_len = bufsize; 34539214Sgibbs ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize); 34669471Sjedgar if (ccb.cdm.matches == NULL) { 34769471Sjedgar warnx("can't malloc memory for matches"); 34869471Sjedgar close(fd); 34969471Sjedgar return(1); 35069471Sjedgar } 35139214Sgibbs ccb.cdm.num_matches = 0; 35239214Sgibbs 35339214Sgibbs /* 35439214Sgibbs * We fetch all nodes, since we display most of them in the default 35539214Sgibbs * case, and all in the verbose case. 35639214Sgibbs */ 35739214Sgibbs ccb.cdm.num_patterns = 0; 35839214Sgibbs ccb.cdm.pattern_buf_len = 0; 35939214Sgibbs 36039214Sgibbs /* 36139214Sgibbs * We do the ioctl multiple times if necessary, in case there are 36239214Sgibbs * more than 100 nodes in the EDT. 36339214Sgibbs */ 36439214Sgibbs do { 36539214Sgibbs if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 36639214Sgibbs warn("error sending CAMIOCOMMAND ioctl"); 36739214Sgibbs error = 1; 36839214Sgibbs break; 36939214Sgibbs } 37039214Sgibbs 37139214Sgibbs if ((ccb.ccb_h.status != CAM_REQ_CMP) 37239214Sgibbs || ((ccb.cdm.status != CAM_DEV_MATCH_LAST) 37339214Sgibbs && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { 37489515Sken warnx("got CAM error %#x, CDM error %d\n", 37589515Sken ccb.ccb_h.status, ccb.cdm.status); 37639214Sgibbs error = 1; 37739214Sgibbs break; 37839214Sgibbs } 37939214Sgibbs 38039214Sgibbs for (i = 0; i < ccb.cdm.num_matches; i++) { 38189515Sken switch (ccb.cdm.matches[i].type) { 38239214Sgibbs case DEV_MATCH_BUS: { 38339214Sgibbs struct bus_match_result *bus_result; 38439214Sgibbs 38539214Sgibbs /* 38639214Sgibbs * Only print the bus information if the 38739214Sgibbs * user turns on the verbose flag. 38839214Sgibbs */ 38939214Sgibbs if ((arglist & CAM_ARG_VERBOSE) == 0) 39039214Sgibbs break; 39139214Sgibbs 39239214Sgibbs bus_result = 39339214Sgibbs &ccb.cdm.matches[i].result.bus_result; 39439214Sgibbs 39539214Sgibbs if (need_close) { 39639214Sgibbs fprintf(stdout, ")\n"); 39739214Sgibbs need_close = 0; 39839214Sgibbs } 39939214Sgibbs 40039214Sgibbs fprintf(stdout, "scbus%d on %s%d bus %d:\n", 40139214Sgibbs bus_result->path_id, 40239214Sgibbs bus_result->dev_name, 40339214Sgibbs bus_result->unit_number, 40439214Sgibbs bus_result->bus_id); 40539214Sgibbs break; 40639214Sgibbs } 40739214Sgibbs case DEV_MATCH_DEVICE: { 40839214Sgibbs struct device_match_result *dev_result; 40939214Sgibbs char vendor[16], product[48], revision[16]; 41039214Sgibbs char tmpstr[256]; 41139214Sgibbs 41239214Sgibbs dev_result = 41339214Sgibbs &ccb.cdm.matches[i].result.device_result; 41439214Sgibbs 41546581Sken if ((dev_result->flags 41646581Sken & DEV_RESULT_UNCONFIGURED) 41746581Sken && ((arglist & CAM_ARG_VERBOSE) == 0)) { 41846581Sken skip_device = 1; 41946581Sken break; 42046581Sken } else 42146581Sken skip_device = 0; 42246581Sken 423195534Sscottl if (dev_result->protocol == PROTO_SCSI) { 424195534Sscottl cam_strvis(vendor, dev_result->inq_data.vendor, 42539214Sgibbs sizeof(dev_result->inq_data.vendor), 42639214Sgibbs sizeof(vendor)); 427195534Sscottl cam_strvis(product, 42839214Sgibbs dev_result->inq_data.product, 42939214Sgibbs sizeof(dev_result->inq_data.product), 43039214Sgibbs sizeof(product)); 431195534Sscottl cam_strvis(revision, 43239214Sgibbs dev_result->inq_data.revision, 43339214Sgibbs sizeof(dev_result->inq_data.revision), 43439214Sgibbs sizeof(revision)); 435195534Sscottl sprintf(tmpstr, "<%s %s %s>", vendor, product, 43639214Sgibbs revision); 437195534Sscottl } else if (dev_result->protocol == PROTO_ATA || 438195534Sscottl dev_result->protocol == PROTO_SATAPM) { 439195534Sscottl cam_strvis(product, 440195534Sscottl dev_result->ident_data.model, 441195534Sscottl sizeof(dev_result->ident_data.model), 442195534Sscottl sizeof(product)); 443195534Sscottl cam_strvis(revision, 444195534Sscottl dev_result->ident_data.revision, 445195534Sscottl sizeof(dev_result->ident_data.revision), 446195534Sscottl sizeof(revision)); 447195534Sscottl sprintf(tmpstr, "<%s %s>", product, 448195534Sscottl revision); 449195534Sscottl } else { 450195534Sscottl sprintf(tmpstr, "<>"); 451195534Sscottl } 45239214Sgibbs if (need_close) { 45339214Sgibbs fprintf(stdout, ")\n"); 45439214Sgibbs need_close = 0; 45539214Sgibbs } 45639214Sgibbs 45739214Sgibbs fprintf(stdout, "%-33s at scbus%d " 45839214Sgibbs "target %d lun %d (", 45939214Sgibbs tmpstr, 46039214Sgibbs dev_result->path_id, 46139214Sgibbs dev_result->target_id, 46239214Sgibbs dev_result->target_lun); 46342647Sgibbs 46442647Sgibbs need_close = 1; 46542647Sgibbs 46639214Sgibbs break; 46739214Sgibbs } 46839214Sgibbs case DEV_MATCH_PERIPH: { 46939214Sgibbs struct periph_match_result *periph_result; 47039214Sgibbs 47139214Sgibbs periph_result = 47239214Sgibbs &ccb.cdm.matches[i].result.periph_result; 47339214Sgibbs 47446581Sken if (skip_device != 0) 47546581Sken break; 47646581Sken 47742647Sgibbs if (need_close > 1) 47839214Sgibbs fprintf(stdout, ","); 47939214Sgibbs 48039214Sgibbs fprintf(stdout, "%s%d", 48139214Sgibbs periph_result->periph_name, 48239214Sgibbs periph_result->unit_number); 48339214Sgibbs 48442647Sgibbs need_close++; 48539214Sgibbs break; 48639214Sgibbs } 48739214Sgibbs default: 48839214Sgibbs fprintf(stdout, "unknown match type\n"); 48939214Sgibbs break; 49039214Sgibbs } 49139214Sgibbs } 49239214Sgibbs 49339214Sgibbs } while ((ccb.ccb_h.status == CAM_REQ_CMP) 49439214Sgibbs && (ccb.cdm.status == CAM_DEV_MATCH_MORE)); 49539214Sgibbs 49639214Sgibbs if (need_close) 49739214Sgibbs fprintf(stdout, ")\n"); 49839214Sgibbs 49939214Sgibbs close(fd); 50039214Sgibbs 50139214Sgibbs return(error); 50239214Sgibbs} 50339214Sgibbs 50489521Sjoerg#ifndef MINIMALISTIC 50539214Sgibbsstatic int 50646581Skentestunitready(struct cam_device *device, int retry_count, int timeout, 50746581Sken int quiet) 50839214Sgibbs{ 50939214Sgibbs int error = 0; 51039214Sgibbs union ccb *ccb; 51139214Sgibbs 51239214Sgibbs ccb = cam_getccb(device); 51339214Sgibbs 51439214Sgibbs scsi_test_unit_ready(&ccb->csio, 51539214Sgibbs /* retries */ retry_count, 51639214Sgibbs /* cbfcnp */ NULL, 51739214Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 51839214Sgibbs /* sense_len */ SSD_FULL_SIZE, 51939214Sgibbs /* timeout */ timeout ? timeout : 5000); 52039214Sgibbs 52139214Sgibbs /* Disable freezing the device queue */ 52239214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 52339214Sgibbs 52439214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 52539214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 52639214Sgibbs 52739214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 52846581Sken if (quiet == 0) 52946581Sken perror("error sending test unit ready"); 53039214Sgibbs 53139214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 53274840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 53374840Sken CAM_EPF_ALL, stderr); 53439214Sgibbs } 53539214Sgibbs 53639214Sgibbs cam_freeccb(ccb); 53739214Sgibbs return(1); 53839214Sgibbs } 53939214Sgibbs 54046581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 54146581Sken if (quiet == 0) 54246581Sken fprintf(stdout, "Unit is ready\n"); 54346581Sken } else { 54446581Sken if (quiet == 0) 54546581Sken fprintf(stdout, "Unit is not ready\n"); 54639214Sgibbs error = 1; 54739214Sgibbs 54839214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 54974840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 55074840Sken CAM_EPF_ALL, stderr); 55139214Sgibbs } 55239214Sgibbs } 55339214Sgibbs 55439214Sgibbs cam_freeccb(ccb); 55539214Sgibbs 55639214Sgibbs return(error); 55739214Sgibbs} 55839214Sgibbs 55939214Sgibbsstatic int 56039214Sgibbsscsistart(struct cam_device *device, int startstop, int loadeject, 56139214Sgibbs int retry_count, int timeout) 56239214Sgibbs{ 56339214Sgibbs union ccb *ccb; 56439214Sgibbs int error = 0; 56539214Sgibbs 56639214Sgibbs ccb = cam_getccb(device); 56739214Sgibbs 56840319Sken /* 56940319Sken * If we're stopping, send an ordered tag so the drive in question 57040319Sken * will finish any previously queued writes before stopping. If 57140319Sken * the device isn't capable of tagged queueing, or if tagged 57240319Sken * queueing is turned off, the tag action is a no-op. 57340319Sken */ 57439214Sgibbs scsi_start_stop(&ccb->csio, 57539214Sgibbs /* retries */ retry_count, 57639214Sgibbs /* cbfcnp */ NULL, 57740319Sken /* tag_action */ startstop ? MSG_SIMPLE_Q_TAG : 57840319Sken MSG_ORDERED_Q_TAG, 57939214Sgibbs /* start/stop */ startstop, 58039214Sgibbs /* load_eject */ loadeject, 58139214Sgibbs /* immediate */ 0, 58239214Sgibbs /* sense_len */ SSD_FULL_SIZE, 58339214Sgibbs /* timeout */ timeout ? timeout : 120000); 58439214Sgibbs 58539214Sgibbs /* Disable freezing the device queue */ 58639214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 58739214Sgibbs 58839214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 58939214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 59039214Sgibbs 59139214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 59239214Sgibbs perror("error sending start unit"); 59339214Sgibbs 59439214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 59574840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 59674840Sken CAM_EPF_ALL, stderr); 59739214Sgibbs } 59839214Sgibbs 59939214Sgibbs cam_freeccb(ccb); 60039214Sgibbs return(1); 60139214Sgibbs } 60239214Sgibbs 60339214Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 60439214Sgibbs if (startstop) { 60539214Sgibbs fprintf(stdout, "Unit started successfully"); 60639214Sgibbs if (loadeject) 60739214Sgibbs fprintf(stdout,", Media loaded\n"); 60839214Sgibbs else 60939214Sgibbs fprintf(stdout,"\n"); 61039214Sgibbs } else { 61139214Sgibbs fprintf(stdout, "Unit stopped successfully"); 61239214Sgibbs if (loadeject) 61339214Sgibbs fprintf(stdout, ", Media ejected\n"); 61439214Sgibbs else 61539214Sgibbs fprintf(stdout, "\n"); 61639214Sgibbs } 61739214Sgibbs else { 61839214Sgibbs error = 1; 61939214Sgibbs if (startstop) 62039214Sgibbs fprintf(stdout, 62139214Sgibbs "Error received from start unit command\n"); 62239214Sgibbs else 62339214Sgibbs fprintf(stdout, 62439214Sgibbs "Error received from stop unit command\n"); 625214321Smav 62639214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 62774840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 62874840Sken CAM_EPF_ALL, stderr); 62939214Sgibbs } 63039214Sgibbs } 63139214Sgibbs 63239214Sgibbs cam_freeccb(ccb); 63339214Sgibbs 63439214Sgibbs return(error); 63539214Sgibbs} 63639214Sgibbs 63739214Sgibbsstatic int 63839214Sgibbsscsidoinquiry(struct cam_device *device, int argc, char **argv, 63939214Sgibbs char *combinedopt, int retry_count, int timeout) 64039214Sgibbs{ 64139214Sgibbs int c; 64239214Sgibbs int error = 0; 64339214Sgibbs 64439214Sgibbs while ((c = getopt(argc, argv, combinedopt)) != -1) { 64539214Sgibbs switch(c) { 64639214Sgibbs case 'D': 64739214Sgibbs arglist |= CAM_ARG_GET_STDINQ; 64839214Sgibbs break; 64939214Sgibbs case 'R': 65039214Sgibbs arglist |= CAM_ARG_GET_XFERRATE; 65139214Sgibbs break; 65239214Sgibbs case 'S': 65339214Sgibbs arglist |= CAM_ARG_GET_SERIAL; 65439214Sgibbs break; 65539214Sgibbs default: 65639214Sgibbs break; 65739214Sgibbs } 65839214Sgibbs } 65939214Sgibbs 66039214Sgibbs /* 66139214Sgibbs * If the user didn't specify any inquiry options, he wants all of 66239214Sgibbs * them. 66339214Sgibbs */ 66439214Sgibbs if ((arglist & CAM_ARG_INQ_MASK) == 0) 66539214Sgibbs arglist |= CAM_ARG_INQ_MASK; 66639214Sgibbs 66739214Sgibbs if (arglist & CAM_ARG_GET_STDINQ) 66839214Sgibbs error = scsiinquiry(device, retry_count, timeout); 66939214Sgibbs 67039214Sgibbs if (error != 0) 67139214Sgibbs return(error); 67239214Sgibbs 67339214Sgibbs if (arglist & CAM_ARG_GET_SERIAL) 67439214Sgibbs scsiserial(device, retry_count, timeout); 67539214Sgibbs 67639214Sgibbs if (error != 0) 67739214Sgibbs return(error); 67839214Sgibbs 67939214Sgibbs if (arglist & CAM_ARG_GET_XFERRATE) 680198709Smav error = camxferrate(device); 68139214Sgibbs 68239214Sgibbs return(error); 68339214Sgibbs} 68439214Sgibbs 68539214Sgibbsstatic int 68639214Sgibbsscsiinquiry(struct cam_device *device, int retry_count, int timeout) 68739214Sgibbs{ 68839214Sgibbs union ccb *ccb; 68939214Sgibbs struct scsi_inquiry_data *inq_buf; 69039214Sgibbs int error = 0; 691214321Smav 69239214Sgibbs ccb = cam_getccb(device); 69339214Sgibbs 69439214Sgibbs if (ccb == NULL) { 69539214Sgibbs warnx("couldn't allocate CCB"); 69639214Sgibbs return(1); 69739214Sgibbs } 69839214Sgibbs 69939214Sgibbs /* cam_getccb cleans up the header, caller has to zero the payload */ 70046581Sken bzero(&(&ccb->ccb_h)[1], 70146581Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 70239214Sgibbs 70339214Sgibbs inq_buf = (struct scsi_inquiry_data *)malloc( 70439214Sgibbs sizeof(struct scsi_inquiry_data)); 70539214Sgibbs 70639214Sgibbs if (inq_buf == NULL) { 70739214Sgibbs cam_freeccb(ccb); 70839214Sgibbs warnx("can't malloc memory for inquiry\n"); 70939214Sgibbs return(1); 71039214Sgibbs } 71139214Sgibbs bzero(inq_buf, sizeof(*inq_buf)); 71239214Sgibbs 71357349Sken /* 71457349Sken * Note that although the size of the inquiry buffer is the full 71557349Sken * 256 bytes specified in the SCSI spec, we only tell the device 71657349Sken * that we have allocated SHORT_INQUIRY_LENGTH bytes. There are 71757349Sken * two reasons for this: 71857349Sken * 71957349Sken * - The SCSI spec says that when a length field is only 1 byte, 72057349Sken * a value of 0 will be interpreted as 256. Therefore 72157349Sken * scsi_inquiry() will convert an inq_len (which is passed in as 72257349Sken * a u_int32_t, but the field in the CDB is only 1 byte) of 256 72357349Sken * to 0. Evidently, very few devices meet the spec in that 724214321Smav * regard. Some devices, like many Seagate disks, take the 0 as 72557349Sken * 0, and don't return any data. One Pioneer DVD-R drive 72657349Sken * returns more data than the command asked for. 72757349Sken * 72857349Sken * So, since there are numerous devices that just don't work 72957349Sken * right with the full inquiry size, we don't send the full size. 730214321Smav * 73157349Sken * - The second reason not to use the full inquiry data length is 73257349Sken * that we don't need it here. The only reason we issue a 73357349Sken * standard inquiry is to get the vendor name, device name, 73457349Sken * and revision so scsi_print_inquiry() can print them. 73557349Sken * 73657349Sken * If, at some point in the future, more inquiry data is needed for 73757349Sken * some reason, this code should use a procedure similar to the 73857349Sken * probe code. i.e., issue a short inquiry, and determine from 73957349Sken * the additional length passed back from the device how much 74057349Sken * inquiry data the device supports. Once the amount the device 74157349Sken * supports is determined, issue an inquiry for that amount and no 74257349Sken * more. 74357349Sken * 74457349Sken * KDM, 2/18/2000 74557349Sken */ 74639214Sgibbs scsi_inquiry(&ccb->csio, 74739214Sgibbs /* retries */ retry_count, 74839214Sgibbs /* cbfcnp */ NULL, 74939214Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 75039214Sgibbs /* inq_buf */ (u_int8_t *)inq_buf, 75157349Sken /* inq_len */ SHORT_INQUIRY_LENGTH, 75239214Sgibbs /* evpd */ 0, 75339214Sgibbs /* page_code */ 0, 75439214Sgibbs /* sense_len */ SSD_FULL_SIZE, 75539214Sgibbs /* timeout */ timeout ? timeout : 5000); 75639214Sgibbs 75739214Sgibbs /* Disable freezing the device queue */ 75839214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 75939214Sgibbs 76039214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 76139214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 76239214Sgibbs 76339214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 76439214Sgibbs perror("error sending SCSI inquiry"); 76539214Sgibbs 76639214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 76774840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 76874840Sken CAM_EPF_ALL, stderr); 76939214Sgibbs } 77039214Sgibbs 77139214Sgibbs cam_freeccb(ccb); 77239214Sgibbs return(1); 77339214Sgibbs } 77439214Sgibbs 77539214Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 77639214Sgibbs error = 1; 77739214Sgibbs 77839214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 77974840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 78074840Sken CAM_EPF_ALL, stderr); 78139214Sgibbs } 78239214Sgibbs } 78339214Sgibbs 78439214Sgibbs cam_freeccb(ccb); 78539214Sgibbs 78639214Sgibbs if (error != 0) { 78739214Sgibbs free(inq_buf); 78839214Sgibbs return(error); 78939214Sgibbs } 79039214Sgibbs 79146581Sken fprintf(stdout, "%s%d: ", device->device_name, 79246581Sken device->dev_unit_num); 79339214Sgibbs scsi_print_inquiry(inq_buf); 79439214Sgibbs 79539214Sgibbs free(inq_buf); 79639214Sgibbs 79739214Sgibbs return(0); 79839214Sgibbs} 79939214Sgibbs 80039214Sgibbsstatic int 80139214Sgibbsscsiserial(struct cam_device *device, int retry_count, int timeout) 80239214Sgibbs{ 80339214Sgibbs union ccb *ccb; 80439214Sgibbs struct scsi_vpd_unit_serial_number *serial_buf; 80539214Sgibbs char serial_num[SVPD_SERIAL_NUM_SIZE + 1]; 80639214Sgibbs int error = 0; 80739214Sgibbs 80839214Sgibbs ccb = cam_getccb(device); 80939214Sgibbs 81039214Sgibbs if (ccb == NULL) { 81139214Sgibbs warnx("couldn't allocate CCB"); 81239214Sgibbs return(1); 81339214Sgibbs } 81439214Sgibbs 81539214Sgibbs /* cam_getccb cleans up the header, caller has to zero the payload */ 81646581Sken bzero(&(&ccb->ccb_h)[1], 81746581Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 81839214Sgibbs 81939214Sgibbs serial_buf = (struct scsi_vpd_unit_serial_number *) 82039214Sgibbs malloc(sizeof(*serial_buf)); 82139214Sgibbs 82239214Sgibbs if (serial_buf == NULL) { 82339214Sgibbs cam_freeccb(ccb); 82439214Sgibbs warnx("can't malloc memory for serial number"); 82539214Sgibbs return(1); 82639214Sgibbs } 82739214Sgibbs 82839214Sgibbs scsi_inquiry(&ccb->csio, 82939214Sgibbs /*retries*/ retry_count, 83039214Sgibbs /*cbfcnp*/ NULL, 83139214Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 83239214Sgibbs /* inq_buf */ (u_int8_t *)serial_buf, 83339214Sgibbs /* inq_len */ sizeof(*serial_buf), 83439214Sgibbs /* evpd */ 1, 83539214Sgibbs /* page_code */ SVPD_UNIT_SERIAL_NUMBER, 83639214Sgibbs /* sense_len */ SSD_FULL_SIZE, 83739214Sgibbs /* timeout */ timeout ? timeout : 5000); 83839214Sgibbs 83939214Sgibbs /* Disable freezing the device queue */ 84039214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 84139214Sgibbs 84239214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 84339214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 84439214Sgibbs 84539214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 84639214Sgibbs warn("error getting serial number"); 84739214Sgibbs 84839214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 84974840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 85074840Sken CAM_EPF_ALL, stderr); 85139214Sgibbs } 85239214Sgibbs 85339214Sgibbs cam_freeccb(ccb); 85439214Sgibbs free(serial_buf); 85539214Sgibbs return(1); 85639214Sgibbs } 85739214Sgibbs 85839214Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 85939214Sgibbs error = 1; 86039214Sgibbs 86139214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 86274840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 86374840Sken CAM_EPF_ALL, stderr); 86439214Sgibbs } 86539214Sgibbs } 86639214Sgibbs 86739214Sgibbs cam_freeccb(ccb); 86839214Sgibbs 86939214Sgibbs if (error != 0) { 87039214Sgibbs free(serial_buf); 87139214Sgibbs return(error); 87239214Sgibbs } 87339214Sgibbs 87439214Sgibbs bcopy(serial_buf->serial_num, serial_num, serial_buf->length); 87539214Sgibbs serial_num[serial_buf->length] = '\0'; 87639214Sgibbs 87746581Sken if ((arglist & CAM_ARG_GET_STDINQ) 87846581Sken || (arglist & CAM_ARG_GET_XFERRATE)) 87946581Sken fprintf(stdout, "%s%d: Serial Number ", 88046581Sken device->device_name, device->dev_unit_num); 88139214Sgibbs 88239214Sgibbs fprintf(stdout, "%.60s\n", serial_num); 88339214Sgibbs 88439214Sgibbs free(serial_buf); 88539214Sgibbs 88639214Sgibbs return(0); 88739214Sgibbs} 88839214Sgibbs 88939214Sgibbsstatic int 890198709Smavcamxferrate(struct cam_device *device) 89139214Sgibbs{ 892198709Smav struct ccb_pathinq cpi; 893163896Smjacob u_int32_t freq = 0; 894163896Smjacob u_int32_t speed = 0; 89546581Sken union ccb *ccb; 89646581Sken u_int mb; 89746581Sken int retval = 0; 89839214Sgibbs 899198709Smav if ((retval = get_cpi(device, &cpi)) != 0) 900198709Smav return (1); 901198709Smav 90246581Sken ccb = cam_getccb(device); 90346581Sken 90446581Sken if (ccb == NULL) { 90546581Sken warnx("couldn't allocate CCB"); 90646581Sken return(1); 90746581Sken } 90846581Sken 90946581Sken bzero(&(&ccb->ccb_h)[1], 91046581Sken sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr)); 91146581Sken 91246581Sken ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 913163896Smjacob ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS; 91446581Sken 91546581Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 91646581Sken || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 91769254Skris const char error_string[] = "error getting transfer settings"; 91846581Sken 91946581Sken if (retval < 0) 92046581Sken warn(error_string); 92146581Sken else 92246581Sken warnx(error_string); 92346581Sken 92446581Sken if (arglist & CAM_ARG_VERBOSE) 92574840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 92674840Sken CAM_EPF_ALL, stderr); 92746581Sken 92846581Sken retval = 1; 92946581Sken 93046581Sken goto xferrate_bailout; 93146581Sken 93246581Sken } 93346581Sken 934198709Smav speed = cpi.base_transfer_speed; 935198709Smav freq = 0; 936163896Smjacob if (ccb->cts.transport == XPORT_SPI) { 937163896Smjacob struct ccb_trans_settings_spi *spi = 938163896Smjacob &ccb->cts.xport_specific.spi; 939163896Smjacob 940163896Smjacob if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) { 941163896Smjacob freq = scsi_calc_syncsrate(spi->sync_period); 942163896Smjacob speed = freq; 943163896Smjacob } 944163896Smjacob if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 945163896Smjacob speed *= (0x01 << spi->bus_width); 946163896Smjacob } 947198709Smav } else if (ccb->cts.transport == XPORT_FC) { 948198709Smav struct ccb_trans_settings_fc *fc = 949198709Smav &ccb->cts.xport_specific.fc; 950163896Smjacob 951198709Smav if (fc->valid & CTS_FC_VALID_SPEED) 952198709Smav speed = fc->bitrate; 953198709Smav } else if (ccb->cts.transport == XPORT_SAS) { 954198709Smav struct ccb_trans_settings_sas *sas = 955198709Smav &ccb->cts.xport_specific.sas; 956163896Smjacob 957198709Smav if (sas->valid & CTS_SAS_VALID_SPEED) 958198709Smav speed = sas->bitrate; 959199747Smav } else if (ccb->cts.transport == XPORT_ATA) { 960199747Smav struct ccb_trans_settings_ata *ata = 961199747Smav &ccb->cts.xport_specific.ata; 962199747Smav 963199747Smav if (ata->valid & CTS_ATA_VALID_MODE) 964199747Smav speed = ata_mode2speed(ata->mode); 965198709Smav } else if (ccb->cts.transport == XPORT_SATA) { 966199747Smav struct ccb_trans_settings_sata *sata = 967198709Smav &ccb->cts.xport_specific.sata; 968163896Smjacob 969199747Smav if (sata->valid & CTS_SATA_VALID_REVISION) 970199747Smav speed = ata_revision2speed(sata->revision); 971198709Smav } 972198709Smav 973198709Smav mb = speed / 1000; 974198709Smav if (mb > 0) { 975199747Smav fprintf(stdout, "%s%d: %d.%03dMB/s transfers", 976198709Smav device->device_name, device->dev_unit_num, 977198709Smav mb, speed % 1000); 978198709Smav } else { 979199747Smav fprintf(stdout, "%s%d: %dKB/s transfers", 980198709Smav device->device_name, device->dev_unit_num, 981198709Smav speed); 982198709Smav } 983198709Smav 984198709Smav if (ccb->cts.transport == XPORT_SPI) { 985198709Smav struct ccb_trans_settings_spi *spi = 986198709Smav &ccb->cts.xport_specific.spi; 987198709Smav 988163896Smjacob if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0) 989163896Smjacob && (spi->sync_offset != 0)) 990199747Smav fprintf(stdout, " (%d.%03dMHz, offset %d", freq / 1000, 991163896Smjacob freq % 1000, spi->sync_offset); 992163896Smjacob 993163896Smjacob if (((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) 994163896Smjacob && (spi->bus_width > 0)) { 995163896Smjacob if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0) 996163896Smjacob && (spi->sync_offset != 0)) { 997163896Smjacob fprintf(stdout, ", "); 998163896Smjacob } else { 999163896Smjacob fprintf(stdout, " ("); 1000163896Smjacob } 1001163896Smjacob fprintf(stdout, "%dbit)", 8 * (0x01 << spi->bus_width)); 1002163896Smjacob } else if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0) 1003163896Smjacob && (spi->sync_offset != 0)) { 1004163896Smjacob fprintf(stdout, ")"); 1005163896Smjacob } 1006198709Smav } else if (ccb->cts.transport == XPORT_ATA) { 1007198709Smav struct ccb_trans_settings_ata *ata = 1008198709Smav &ccb->cts.xport_specific.ata; 100946581Sken 1010199747Smav printf(" ("); 1011199747Smav if (ata->valid & CTS_ATA_VALID_MODE) 1012199747Smav printf("%s, ", ata_mode2string(ata->mode)); 1013203376Smav if ((ata->valid & CTS_ATA_VALID_ATAPI) && ata->atapi != 0) 1014203376Smav printf("ATAPI %dbytes, ", ata->atapi); 1015199747Smav if (ata->valid & CTS_ATA_VALID_BYTECOUNT) 1016203376Smav printf("PIO %dbytes", ata->bytecount); 1017199747Smav printf(")"); 1018198709Smav } else if (ccb->cts.transport == XPORT_SATA) { 1019198709Smav struct ccb_trans_settings_sata *sata = 1020198709Smav &ccb->cts.xport_specific.sata; 102146581Sken 1022199747Smav printf(" ("); 1023199747Smav if (sata->valid & CTS_SATA_VALID_REVISION) 1024199747Smav printf("SATA %d.x, ", sata->revision); 1025204195Smav else 1026204195Smav printf("SATA, "); 1027199747Smav if (sata->valid & CTS_SATA_VALID_MODE) 1028199747Smav printf("%s, ", ata_mode2string(sata->mode)); 1029203376Smav if ((sata->valid & CTS_SATA_VALID_ATAPI) && sata->atapi != 0) 1030203376Smav printf("ATAPI %dbytes, ", sata->atapi); 1031199747Smav if (sata->valid & CTS_SATA_VALID_BYTECOUNT) 1032203376Smav printf("PIO %dbytes", sata->bytecount); 1033199747Smav printf(")"); 1034163896Smjacob } 103539214Sgibbs 1036163896Smjacob if (ccb->cts.protocol == PROTO_SCSI) { 1037163896Smjacob struct ccb_trans_settings_scsi *scsi = 1038163896Smjacob &ccb->cts.proto_specific.scsi; 1039163896Smjacob if (scsi->valid & CTS_SCSI_VALID_TQ) { 1040164842Smjacob if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) { 1041163896Smjacob fprintf(stdout, ", Command Queueing Enabled"); 1042164842Smjacob } 104346581Sken } 104446581Sken } 104546581Sken 104639214Sgibbs fprintf(stdout, "\n"); 104739214Sgibbs 104846581Skenxferrate_bailout: 104946581Sken 105046581Sken cam_freeccb(ccb); 105146581Sken 105246581Sken return(retval); 105339214Sgibbs} 1054195534Sscottl 1055195534Sscottlstatic void 1056195534Sscottlatacapprint(struct ata_params *parm) 1057195534Sscottl{ 1058195534Sscottl u_int32_t lbasize = (u_int32_t)parm->lba_size_1 | 1059195534Sscottl ((u_int32_t)parm->lba_size_2 << 16); 1060195534Sscottl 1061195534Sscottl u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) | 1062195534Sscottl ((u_int64_t)parm->lba_size48_2 << 16) | 1063195534Sscottl ((u_int64_t)parm->lba_size48_3 << 32) | 1064195534Sscottl ((u_int64_t)parm->lba_size48_4 << 48); 1065195534Sscottl 1066195534Sscottl printf("\n"); 1067196658Smav printf("protocol "); 1068196658Smav printf("ATA/ATAPI-%d", ata_version(parm->version_major)); 1069195534Sscottl if (parm->satacapabilities && parm->satacapabilities != 0xffff) { 1070197545Smav if (parm->satacapabilities & ATA_SATA_GEN3) 1071197545Smav printf(" SATA 3.x\n"); 1072197545Smav else if (parm->satacapabilities & ATA_SATA_GEN2) 1073196658Smav printf(" SATA 2.x\n"); 1074195534Sscottl else if (parm->satacapabilities & ATA_SATA_GEN1) 1075196658Smav printf(" SATA 1.x\n"); 1076195534Sscottl else 1077197545Smav printf(" SATA\n"); 1078195534Sscottl } 1079195534Sscottl else 1080196658Smav printf("\n"); 1081195534Sscottl printf("device model %.40s\n", parm->model); 1082197545Smav printf("firmware revision %.8s\n", parm->revision); 1083195534Sscottl printf("serial number %.20s\n", parm->serial); 1084197545Smav if (parm->enabled.extension & ATA_SUPPORT_64BITWWN) { 1085197545Smav printf("WWN %02x%02x%02x%02x\n", 1086197545Smav parm->wwn[0], parm->wwn[1], parm->wwn[2], parm->wwn[3]); 1087197545Smav } 1088197545Smav if (parm->enabled.extension & ATA_SUPPORT_MEDIASN) { 1089197545Smav printf("media serial number %.30s\n", 1090197545Smav parm->media_serial); 1091197545Smav } 1092195534Sscottl 1093195534Sscottl printf("cylinders %d\n", parm->cylinders); 1094195534Sscottl printf("heads %d\n", parm->heads); 1095195534Sscottl printf("sectors/track %d\n", parm->sectors); 1096198897Smav printf("sector size logical %u, physical %lu, offset %lu\n", 1097198897Smav ata_logical_sector_size(parm), 1098198897Smav (unsigned long)ata_physical_sector_size(parm), 1099198897Smav (unsigned long)ata_logical_sector_offset(parm)); 1100195534Sscottl 1101195534Sscottl if (parm->config == ATA_PROTO_CFA || 1102195534Sscottl (parm->support.command2 & ATA_SUPPORT_CFA)) 1103195534Sscottl printf("CFA supported\n"); 1104195534Sscottl 1105196658Smav printf("LBA%ssupported ", 1106195534Sscottl parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not "); 1107195534Sscottl if (lbasize) 1108195534Sscottl printf("%d sectors\n", lbasize); 1109195534Sscottl else 1110195534Sscottl printf("\n"); 1111195534Sscottl 1112196658Smav printf("LBA48%ssupported ", 1113195534Sscottl parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not "); 1114195534Sscottl if (lbasize48) 1115195534Sscottl printf("%ju sectors\n", (uintmax_t)lbasize48); 1116195534Sscottl else 1117195534Sscottl printf("\n"); 1118195534Sscottl 1119196658Smav printf("PIO supported PIO"); 1120197419Smav switch (ata_max_pmode(parm)) { 1121197419Smav case ATA_PIO4: 1122196658Smav printf("4"); 1123197419Smav break; 1124197419Smav case ATA_PIO3: 1125196658Smav printf("3"); 1126197419Smav break; 1127197419Smav case ATA_PIO2: 1128196658Smav printf("2"); 1129197419Smav break; 1130197419Smav case ATA_PIO1: 1131196658Smav printf("1"); 1132197419Smav break; 1133197419Smav default: 1134196658Smav printf("0"); 1135197419Smav } 1136197545Smav if ((parm->capabilities1 & ATA_SUPPORT_IORDY) == 0) 1137197545Smav printf(" w/o IORDY"); 1138196658Smav printf("\n"); 1139196658Smav 1140196658Smav printf("DMA%ssupported ", 1141195534Sscottl parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not "); 1142196658Smav if (parm->capabilities1 & ATA_SUPPORT_DMA) { 1143196658Smav if (parm->mwdmamodes & 0xff) { 1144196658Smav printf("WDMA"); 1145196658Smav if (parm->mwdmamodes & 0x04) 1146196658Smav printf("2"); 1147196658Smav else if (parm->mwdmamodes & 0x02) 1148196658Smav printf("1"); 1149196658Smav else if (parm->mwdmamodes & 0x01) 1150196658Smav printf("0"); 1151196658Smav printf(" "); 1152196658Smav } 1153196658Smav if ((parm->atavalid & ATA_FLAG_88) && 1154196658Smav (parm->udmamodes & 0xff)) { 1155196658Smav printf("UDMA"); 1156196658Smav if (parm->udmamodes & 0x40) 1157196658Smav printf("6"); 1158196658Smav else if (parm->udmamodes & 0x20) 1159196658Smav printf("5"); 1160196658Smav else if (parm->udmamodes & 0x10) 1161196658Smav printf("4"); 1162196658Smav else if (parm->udmamodes & 0x08) 1163196658Smav printf("3"); 1164196658Smav else if (parm->udmamodes & 0x04) 1165196658Smav printf("2"); 1166196658Smav else if (parm->udmamodes & 0x02) 1167196658Smav printf("1"); 1168196658Smav else if (parm->udmamodes & 0x01) 1169196658Smav printf("0"); 1170196658Smav printf(" "); 1171196658Smav } 1172196658Smav } 1173196658Smav printf("\n"); 1174195534Sscottl 1175197545Smav if (parm->media_rotation_rate == 1) { 1176197545Smav printf("media RPM non-rotating\n"); 1177197545Smav } else if (parm->media_rotation_rate >= 0x0401 && 1178197545Smav parm->media_rotation_rate <= 0xFFFE) { 1179197545Smav printf("media RPM %d\n", 1180197545Smav parm->media_rotation_rate); 1181197545Smav } 1182195534Sscottl 1183195534Sscottl printf("\nFeature " 1184214321Smav "Support Enabled Value Vendor\n"); 1185197545Smav printf("read ahead %s %s\n", 1186197545Smav parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no", 1187197545Smav parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no"); 1188195534Sscottl printf("write cache %s %s\n", 1189195534Sscottl parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no", 1190195534Sscottl parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no"); 1191197545Smav printf("flush cache %s %s\n", 1192197545Smav parm->support.command2 & ATA_SUPPORT_FLUSHCACHE ? "yes" : "no", 1193197545Smav parm->enabled.command2 & ATA_SUPPORT_FLUSHCACHE ? "yes" : "no"); 1194202694Smav printf("overlap %s\n", 1195202694Smav parm->capabilities1 & ATA_SUPPORT_OVERLAP ? "yes" : "no"); 1196202694Smav printf("Tagged Command Queuing (TCQ) %s %s", 1197202694Smav parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no", 1198202694Smav parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no"); 1199202694Smav if (parm->support.command2 & ATA_SUPPORT_QUEUED) { 1200202694Smav printf(" %d tags\n", 1201202694Smav ATA_QUEUE_LEN(parm->queue) + 1); 1202202694Smav } else 1203202694Smav printf("\n"); 1204214321Smav printf("Native Command Queuing (NCQ) "); 1205214321Smav if (parm->satacapabilities != 0xffff && 1206214321Smav (parm->satacapabilities & ATA_SUPPORT_NCQ)) { 1207214321Smav printf("yes %d tags\n", 1208214321Smav ATA_QUEUE_LEN(parm->queue) + 1); 1209214321Smav } else 1210214321Smav printf("no\n"); 1211195534Sscottl printf("SMART %s %s\n", 1212195534Sscottl parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no", 1213195534Sscottl parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no"); 1214195534Sscottl printf("microcode download %s %s\n", 1215195534Sscottl parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no", 1216195534Sscottl parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no"); 1217195534Sscottl printf("security %s %s\n", 1218195534Sscottl parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no", 1219195534Sscottl parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no"); 1220195534Sscottl printf("power management %s %s\n", 1221195534Sscottl parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no", 1222195534Sscottl parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no"); 1223214321Smav printf("advanced power management %s %s", 1224195534Sscottl parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no", 1225214321Smav parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no"); 1226214321Smav if (parm->support.command2 & ATA_SUPPORT_APM) { 1227214321Smav printf(" %d/0x%02X\n", 1228214321Smav parm->apm_value, parm->apm_value); 1229214321Smav } else 1230214321Smav printf("\n"); 1231214321Smav printf("automatic acoustic management %s %s", 1232195534Sscottl parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no", 1233214321Smav parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no"); 1234214321Smav if (parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC) { 1235214321Smav printf(" %d/0x%02X %d/0x%02X\n", 1236214321Smav ATA_ACOUSTIC_CURRENT(parm->acoustic), 1237214321Smav ATA_ACOUSTIC_CURRENT(parm->acoustic), 1238214321Smav ATA_ACOUSTIC_VENDOR(parm->acoustic), 1239214321Smav ATA_ACOUSTIC_VENDOR(parm->acoustic)); 1240214321Smav } else 1241214321Smav printf("\n"); 1242197545Smav printf("media status notification %s %s\n", 1243197545Smav parm->support.command2 & ATA_SUPPORT_NOTIFY ? "yes" : "no", 1244197545Smav parm->enabled.command2 & ATA_SUPPORT_NOTIFY ? "yes" : "no"); 1245197545Smav printf("power-up in Standby %s %s\n", 1246197545Smav parm->support.command2 & ATA_SUPPORT_STANDBY ? "yes" : "no", 1247197545Smav parm->enabled.command2 & ATA_SUPPORT_STANDBY ? "yes" : "no"); 1248214321Smav printf("write-read-verify %s %s", 1249197545Smav parm->support2 & ATA_SUPPORT_WRITEREADVERIFY ? "yes" : "no", 1250214321Smav parm->enabled2 & ATA_SUPPORT_WRITEREADVERIFY ? "yes" : "no"); 1251214321Smav if (parm->support2 & ATA_SUPPORT_WRITEREADVERIFY) { 1252214321Smav printf(" %d/0x%x\n", 1253214321Smav parm->wrv_mode, parm->wrv_mode); 1254214321Smav } else 1255214321Smav printf("\n"); 1256197545Smav printf("unload %s %s\n", 1257197545Smav parm->support.extension & ATA_SUPPORT_UNLOAD ? "yes" : "no", 1258197545Smav parm->enabled.extension & ATA_SUPPORT_UNLOAD ? "yes" : "no"); 1259197545Smav printf("free-fall %s %s\n", 1260197545Smav parm->support2 & ATA_SUPPORT_FREEFALL ? "yes" : "no", 1261197545Smav parm->enabled2 & ATA_SUPPORT_FREEFALL ? "yes" : "no"); 1262202694Smav printf("data set management (TRIM) %s\n", 1263202694Smav parm->support_dsm & ATA_SUPPORT_DSM_TRIM ? "yes" : "no"); 1264195534Sscottl} 1265195534Sscottl 1266195534Sscottlstatic int 1267195534Sscottlataidentify(struct cam_device *device, int retry_count, int timeout) 1268195534Sscottl{ 1269195534Sscottl union ccb *ccb; 1270195534Sscottl struct ata_params *ident_buf; 1271196658Smav struct ccb_getdev cgd; 1272195573Sscottl u_int i, error = 0; 1273195534Sscottl int16_t *ptr; 1274196658Smav 1275196658Smav if (get_cgd(device, &cgd) != 0) { 1276196658Smav warnx("couldn't get CGD"); 1277196658Smav return(1); 1278196658Smav } 1279195534Sscottl ccb = cam_getccb(device); 1280195534Sscottl 1281195534Sscottl if (ccb == NULL) { 1282195534Sscottl warnx("couldn't allocate CCB"); 1283195534Sscottl return(1); 1284195534Sscottl } 1285195534Sscottl 1286195534Sscottl /* cam_getccb cleans up the header, caller has to zero the payload */ 1287195534Sscottl bzero(&(&ccb->ccb_h)[1], 1288195534Sscottl sizeof(struct ccb_ataio) - sizeof(struct ccb_hdr)); 1289195534Sscottl 1290195573Sscottl ptr = (uint16_t *)malloc(sizeof(struct ata_params)); 1291195534Sscottl 1292195573Sscottl if (ptr == NULL) { 1293195534Sscottl cam_freeccb(ccb); 1294195534Sscottl warnx("can't malloc memory for identify\n"); 1295195534Sscottl return(1); 1296195534Sscottl } 1297195573Sscottl bzero(ptr, sizeof(struct ata_params)); 1298195534Sscottl 1299195534Sscottl cam_fill_ataio(&ccb->ataio, 1300195534Sscottl retry_count, 1301195534Sscottl NULL, 1302195534Sscottl /*flags*/CAM_DIR_IN, 1303195534Sscottl MSG_SIMPLE_Q_TAG, 1304195573Sscottl /*data_ptr*/(u_int8_t *)ptr, 1305195534Sscottl /*dxfer_len*/sizeof(struct ata_params), 1306195534Sscottl timeout ? timeout : 30 * 1000); 1307196658Smav if (cgd.protocol == PROTO_ATA) 1308196659Smav ata_28bit_cmd(&ccb->ataio, ATA_ATA_IDENTIFY, 0, 0, 0); 1309196658Smav else 1310196659Smav ata_28bit_cmd(&ccb->ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0); 1311195534Sscottl 1312195534Sscottl /* Disable freezing the device queue */ 1313195534Sscottl ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 1314195534Sscottl 1315195534Sscottl if (arglist & CAM_ARG_ERR_RECOVER) 1316195534Sscottl ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 1317195534Sscottl 1318195534Sscottl if (cam_send_ccb(device, ccb) < 0) { 1319195534Sscottl perror("error sending ATA identify"); 1320195534Sscottl 1321195534Sscottl if (arglist & CAM_ARG_VERBOSE) { 1322195534Sscottl cam_error_print(device, ccb, CAM_ESF_ALL, 1323195534Sscottl CAM_EPF_ALL, stderr); 1324195534Sscottl } 1325195534Sscottl 1326195573Sscottl free(ptr); 1327195534Sscottl cam_freeccb(ccb); 1328195534Sscottl return(1); 1329195534Sscottl } 1330195534Sscottl 1331195534Sscottl if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1332195534Sscottl error = 1; 1333195534Sscottl 1334195534Sscottl if (arglist & CAM_ARG_VERBOSE) { 1335195534Sscottl cam_error_print(device, ccb, CAM_ESF_ALL, 1336195534Sscottl CAM_EPF_ALL, stderr); 1337195534Sscottl } 1338195534Sscottl } 1339195534Sscottl 1340195534Sscottl cam_freeccb(ccb); 1341195534Sscottl 1342195534Sscottl if (error != 0) { 1343195573Sscottl free(ptr); 1344195534Sscottl return(error); 1345195534Sscottl } 1346195534Sscottl 1347195573Sscottl for (i = 0; i < sizeof(struct ata_params) / 2; i++) 1348195573Sscottl ptr[i] = le16toh(ptr[i]); 1349202694Smav if (arglist & CAM_ARG_VERBOSE) { 1350202694Smav fprintf(stdout, "%s%d: Raw identify data:\n", 1351202694Smav device->device_name, device->dev_unit_num); 1352202694Smav for (i = 0; i < sizeof(struct ata_params) / 2; i++) { 1353202694Smav if ((i % 8) == 0) 1354202694Smav fprintf(stdout, " %3d: ", i); 1355202694Smav fprintf(stdout, "%04x ", (uint16_t)ptr[i]); 1356202694Smav if ((i % 8) == 7) 1357202694Smav fprintf(stdout, "\n"); 1358202694Smav } 1359202694Smav } 1360195573Sscottl ident_buf = (struct ata_params *)ptr; 1361195534Sscottl if (strncmp(ident_buf->model, "FX", 2) && 1362195534Sscottl strncmp(ident_buf->model, "NEC", 3) && 1363195534Sscottl strncmp(ident_buf->model, "Pioneer", 7) && 1364195534Sscottl strncmp(ident_buf->model, "SHARP", 5)) { 1365195534Sscottl ata_bswap(ident_buf->model, sizeof(ident_buf->model)); 1366195534Sscottl ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); 1367195534Sscottl ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); 1368197545Smav ata_bswap(ident_buf->media_serial, sizeof(ident_buf->media_serial)); 1369195534Sscottl } 1370195534Sscottl ata_btrim(ident_buf->model, sizeof(ident_buf->model)); 1371195534Sscottl ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); 1372195534Sscottl ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); 1373195534Sscottl ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); 1374195534Sscottl ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); 1375195534Sscottl ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); 1376197545Smav ata_btrim(ident_buf->media_serial, sizeof(ident_buf->media_serial)); 1377197545Smav ata_bpack(ident_buf->media_serial, ident_buf->media_serial, 1378197545Smav sizeof(ident_buf->media_serial)); 1379195534Sscottl 1380195534Sscottl fprintf(stdout, "%s%d: ", device->device_name, 1381195534Sscottl device->dev_unit_num); 1382195534Sscottl ata_print_ident(ident_buf); 1383198709Smav camxferrate(device); 1384195534Sscottl atacapprint(ident_buf); 1385195534Sscottl 1386195534Sscottl free(ident_buf); 1387195534Sscottl 1388195534Sscottl return(0); 1389195534Sscottl} 139089471Sjoerg#endif /* MINIMALISTIC */ 139139214Sgibbs 139246938Sken/* 139346938Sken * Parse out a bus, or a bus, target and lun in the following 139446938Sken * format: 139546938Sken * bus 139646938Sken * bus:target 139746938Sken * bus:target:lun 139846938Sken * 139946938Sken * Returns the number of parsed components, or 0. 140046938Sken */ 140139214Sgibbsstatic int 1402118478Sjohanparse_btl(char *tstr, int *bus, int *target, int *lun, cam_argmask *arglst) 140346938Sken{ 140446938Sken char *tmpstr; 140546938Sken int convs = 0; 140646938Sken 140746938Sken while (isspace(*tstr) && (*tstr != '\0')) 140846938Sken tstr++; 140946938Sken 141046938Sken tmpstr = (char *)strtok(tstr, ":"); 141146938Sken if ((tmpstr != NULL) && (*tmpstr != '\0')) { 141246938Sken *bus = strtol(tmpstr, NULL, 0); 1413118478Sjohan *arglst |= CAM_ARG_BUS; 141446938Sken convs++; 141546938Sken tmpstr = (char *)strtok(NULL, ":"); 141646938Sken if ((tmpstr != NULL) && (*tmpstr != '\0')) { 141746938Sken *target = strtol(tmpstr, NULL, 0); 1418118478Sjohan *arglst |= CAM_ARG_TARGET; 141946938Sken convs++; 142046938Sken tmpstr = (char *)strtok(NULL, ":"); 142146938Sken if ((tmpstr != NULL) && (*tmpstr != '\0')) { 142246938Sken *lun = strtol(tmpstr, NULL, 0); 1423118478Sjohan *arglst |= CAM_ARG_LUN; 142446938Sken convs++; 142546938Sken } 142646938Sken } 142746938Sken } 142846938Sken 142946938Sken return convs; 143046938Sken} 143146938Sken 143246938Skenstatic int 143341962Smjacobdorescan_or_reset(int argc, char **argv, int rescan) 143439214Sgibbs{ 143569254Skris static const char must[] = 143689515Sken "you must specify \"all\", a bus, or a bus:target:lun to %s"; 143746938Sken int rv, error = 0; 143839214Sgibbs int bus = -1, target = -1, lun = -1; 143989515Sken char *tstr; 144039214Sgibbs 144139214Sgibbs if (argc < 3) { 144241962Smjacob warnx(must, rescan? "rescan" : "reset"); 144339214Sgibbs return(1); 144439214Sgibbs } 144589515Sken 144689515Sken tstr = argv[optind]; 144789515Sken while (isspace(*tstr) && (*tstr != '\0')) 144889515Sken tstr++; 144989515Sken if (strncasecmp(tstr, "all", strlen("all")) == 0) 145089515Sken arglist |= CAM_ARG_BUS; 145189515Sken else { 145289515Sken rv = parse_btl(argv[optind], &bus, &target, &lun, &arglist); 145389515Sken if (rv != 1 && rv != 3) { 145489515Sken warnx(must, rescan? "rescan" : "reset"); 145589515Sken return(1); 145689515Sken } 145739214Sgibbs } 145839214Sgibbs 145946938Sken if ((arglist & CAM_ARG_BUS) 146046938Sken && (arglist & CAM_ARG_TARGET) 146146938Sken && (arglist & CAM_ARG_LUN)) 146246938Sken error = scanlun_or_reset_dev(bus, target, lun, rescan); 146346938Sken else 146446938Sken error = rescan_or_reset_bus(bus, rescan); 146539214Sgibbs 146639214Sgibbs return(error); 146739214Sgibbs} 146839214Sgibbs 146939214Sgibbsstatic int 147041962Smjacobrescan_or_reset_bus(int bus, int rescan) 147139214Sgibbs{ 147289515Sken union ccb ccb, matchccb; 147389515Sken int fd, retval; 147489515Sken int bufsize; 147539214Sgibbs 147689515Sken retval = 0; 147739214Sgibbs 147839214Sgibbs if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { 1479166324Swilko warnx("error opening transport layer device %s", XPT_DEVICE); 148039214Sgibbs warn("%s", XPT_DEVICE); 148139214Sgibbs return(1); 148239214Sgibbs } 148339214Sgibbs 148489515Sken if (bus != -1) { 148589515Sken ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS : XPT_RESET_BUS; 148689515Sken ccb.ccb_h.path_id = bus; 148789515Sken ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; 148889515Sken ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; 148989515Sken ccb.crcn.flags = CAM_FLAG_NONE; 149039214Sgibbs 149189515Sken /* run this at a low priority */ 149289515Sken ccb.ccb_h.pinfo.priority = 5; 149339214Sgibbs 149489515Sken if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 149589515Sken warn("CAMIOCOMMAND ioctl failed"); 149689515Sken close(fd); 149789515Sken return(1); 149889515Sken } 149989515Sken 150089515Sken if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 150189515Sken fprintf(stdout, "%s of bus %d was successful\n", 150289515Sken rescan ? "Re-scan" : "Reset", bus); 150389515Sken } else { 150489515Sken fprintf(stdout, "%s of bus %d returned error %#x\n", 150589515Sken rescan ? "Re-scan" : "Reset", bus, 150689515Sken ccb.ccb_h.status & CAM_STATUS_MASK); 150789515Sken retval = 1; 150889515Sken } 150989515Sken 151039214Sgibbs close(fd); 151189515Sken return(retval); 151289515Sken 151339214Sgibbs } 151439214Sgibbs 151539214Sgibbs 151689515Sken /* 151789515Sken * The right way to handle this is to modify the xpt so that it can 151889515Sken * handle a wildcarded bus in a rescan or reset CCB. At the moment 151989515Sken * that isn't implemented, so instead we enumerate the busses and 152089515Sken * send the rescan or reset to those busses in the case where the 152189515Sken * given bus is -1 (wildcard). We don't send a rescan or reset 152289515Sken * to the xpt bus; sending a rescan to the xpt bus is effectively a 152389515Sken * no-op, sending a rescan to the xpt bus would result in a status of 152489515Sken * CAM_REQ_INVALID. 152589515Sken */ 152689515Sken bzero(&(&matchccb.ccb_h)[1], 152789515Sken sizeof(struct ccb_dev_match) - sizeof(struct ccb_hdr)); 152889515Sken matchccb.ccb_h.func_code = XPT_DEV_MATCH; 1529215507Srstone matchccb.ccb_h.path_id = CAM_BUS_WILDCARD; 153089515Sken bufsize = sizeof(struct dev_match_result) * 20; 153189515Sken matchccb.cdm.match_buf_len = bufsize; 153289515Sken matchccb.cdm.matches=(struct dev_match_result *)malloc(bufsize); 153389515Sken if (matchccb.cdm.matches == NULL) { 153489515Sken warnx("can't malloc memory for matches"); 153589515Sken retval = 1; 153689515Sken goto bailout; 153739214Sgibbs } 153889515Sken matchccb.cdm.num_matches = 0; 153989515Sken 154089515Sken matchccb.cdm.num_patterns = 1; 154189515Sken matchccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern); 154289515Sken 154389515Sken matchccb.cdm.patterns = (struct dev_match_pattern *)malloc( 154489515Sken matchccb.cdm.pattern_buf_len); 154589515Sken if (matchccb.cdm.patterns == NULL) { 154689515Sken warnx("can't malloc memory for patterns"); 154789515Sken retval = 1; 154889515Sken goto bailout; 154989515Sken } 155089515Sken matchccb.cdm.patterns[0].type = DEV_MATCH_BUS; 155189515Sken matchccb.cdm.patterns[0].pattern.bus_pattern.flags = BUS_MATCH_ANY; 155289515Sken 155389515Sken do { 1554102192Sjohan unsigned int i; 155589515Sken 155689515Sken if (ioctl(fd, CAMIOCOMMAND, &matchccb) == -1) { 155789515Sken warn("CAMIOCOMMAND ioctl failed"); 155889515Sken retval = 1; 155989515Sken goto bailout; 156089515Sken } 156189515Sken 156289515Sken if ((matchccb.ccb_h.status != CAM_REQ_CMP) 156389515Sken || ((matchccb.cdm.status != CAM_DEV_MATCH_LAST) 156489515Sken && (matchccb.cdm.status != CAM_DEV_MATCH_MORE))) { 156589515Sken warnx("got CAM error %#x, CDM error %d\n", 156689515Sken matchccb.ccb_h.status, matchccb.cdm.status); 156789515Sken retval = 1; 156889515Sken goto bailout; 156989515Sken } 157089515Sken 157189515Sken for (i = 0; i < matchccb.cdm.num_matches; i++) { 157289515Sken struct bus_match_result *bus_result; 157389515Sken 157489515Sken /* This shouldn't happen. */ 157589515Sken if (matchccb.cdm.matches[i].type != DEV_MATCH_BUS) 157689515Sken continue; 157789515Sken 157889515Sken bus_result = &matchccb.cdm.matches[i].result.bus_result; 157989515Sken 158089515Sken /* 158189515Sken * We don't want to rescan or reset the xpt bus. 158289515Sken * See above. 158389515Sken */ 1584102192Sjohan if ((int)bus_result->path_id == -1) 158589515Sken continue; 158689515Sken 158789515Sken ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS : 158889515Sken XPT_RESET_BUS; 158989515Sken ccb.ccb_h.path_id = bus_result->path_id; 159089515Sken ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; 159189515Sken ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; 159289515Sken ccb.crcn.flags = CAM_FLAG_NONE; 159389515Sken 159489515Sken /* run this at a low priority */ 159589515Sken ccb.ccb_h.pinfo.priority = 5; 159689515Sken 159789515Sken if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 159889515Sken warn("CAMIOCOMMAND ioctl failed"); 159989515Sken retval = 1; 160089515Sken goto bailout; 160189515Sken } 160289515Sken 160389515Sken if ((ccb.ccb_h.status & CAM_STATUS_MASK) ==CAM_REQ_CMP){ 160489515Sken fprintf(stdout, "%s of bus %d was successful\n", 160589515Sken rescan? "Re-scan" : "Reset", 160689515Sken bus_result->path_id); 160789515Sken } else { 160889515Sken /* 160989515Sken * Don't bail out just yet, maybe the other 161089515Sken * rescan or reset commands will complete 161189515Sken * successfully. 161289515Sken */ 161389515Sken fprintf(stderr, "%s of bus %d returned error " 161489515Sken "%#x\n", rescan? "Re-scan" : "Reset", 161589515Sken bus_result->path_id, 161689515Sken ccb.ccb_h.status & CAM_STATUS_MASK); 161789515Sken retval = 1; 161889515Sken } 161989515Sken } 162089515Sken } while ((matchccb.ccb_h.status == CAM_REQ_CMP) 162189515Sken && (matchccb.cdm.status == CAM_DEV_MATCH_MORE)); 162289515Sken 162389515Skenbailout: 162489515Sken 162589515Sken if (fd != -1) 162689515Sken close(fd); 162789515Sken 162889515Sken if (matchccb.cdm.patterns != NULL) 162989515Sken free(matchccb.cdm.patterns); 163089515Sken if (matchccb.cdm.matches != NULL) 163189515Sken free(matchccb.cdm.matches); 163289515Sken 163389515Sken return(retval); 163439214Sgibbs} 163539214Sgibbs 163639214Sgibbsstatic int 163741962Smjacobscanlun_or_reset_dev(int bus, int target, int lun, int scan) 163839214Sgibbs{ 163939214Sgibbs union ccb ccb; 164052703Sken struct cam_device *device; 164139214Sgibbs int fd; 164239214Sgibbs 164361233Sken device = NULL; 164461233Sken 164539214Sgibbs if (bus < 0) { 164639214Sgibbs warnx("invalid bus number %d", bus); 164739214Sgibbs return(1); 164839214Sgibbs } 164939214Sgibbs 165039214Sgibbs if (target < 0) { 165139214Sgibbs warnx("invalid target number %d", target); 165239214Sgibbs return(1); 165339214Sgibbs } 165439214Sgibbs 165539214Sgibbs if (lun < 0) { 165639214Sgibbs warnx("invalid lun number %d", lun); 165739214Sgibbs return(1); 165839214Sgibbs } 165939214Sgibbs 166052703Sken fd = -1; 166152703Sken 166252703Sken bzero(&ccb, sizeof(union ccb)); 166352703Sken 166452703Sken if (scan) { 166552703Sken if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { 1666166324Swilko warnx("error opening transport layer device %s\n", 166752703Sken XPT_DEVICE); 166852703Sken warn("%s", XPT_DEVICE); 166952703Sken return(1); 167052703Sken } 167152703Sken } else { 167252703Sken device = cam_open_btl(bus, target, lun, O_RDWR, NULL); 167352703Sken if (device == NULL) { 167452703Sken warnx("%s", cam_errbuf); 167552703Sken return(1); 167652703Sken } 167739214Sgibbs } 167839214Sgibbs 167941962Smjacob ccb.ccb_h.func_code = (scan)? XPT_SCAN_LUN : XPT_RESET_DEV; 168039214Sgibbs ccb.ccb_h.path_id = bus; 168139214Sgibbs ccb.ccb_h.target_id = target; 168239214Sgibbs ccb.ccb_h.target_lun = lun; 168352703Sken ccb.ccb_h.timeout = 5000; 168439214Sgibbs ccb.crcn.flags = CAM_FLAG_NONE; 168539214Sgibbs 168639214Sgibbs /* run this at a low priority */ 168739214Sgibbs ccb.ccb_h.pinfo.priority = 5; 168839214Sgibbs 168952703Sken if (scan) { 169052703Sken if (ioctl(fd, CAMIOCOMMAND, &ccb) < 0) { 169152703Sken warn("CAMIOCOMMAND ioctl failed"); 169252703Sken close(fd); 169352703Sken return(1); 169452703Sken } 169552703Sken } else { 169652703Sken if (cam_send_ccb(device, &ccb) < 0) { 169752703Sken warn("error sending XPT_RESET_DEV CCB"); 169852703Sken cam_close_device(device); 169952703Sken return(1); 170052703Sken } 170139214Sgibbs } 170239214Sgibbs 170352703Sken if (scan) 170452703Sken close(fd); 170552703Sken else 170652703Sken cam_close_device(device); 170739214Sgibbs 170852703Sken /* 170952703Sken * An error code of CAM_BDR_SENT is normal for a BDR request. 171052703Sken */ 171152703Sken if (((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 171252703Sken || ((!scan) 171352703Sken && ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_BDR_SENT))) { 171441962Smjacob fprintf(stdout, "%s of %d:%d:%d was successful\n", 171541962Smjacob scan? "Re-scan" : "Reset", bus, target, lun); 171639214Sgibbs return(0); 171739214Sgibbs } else { 171841962Smjacob fprintf(stdout, "%s of %d:%d:%d returned error %#x\n", 171941962Smjacob scan? "Re-scan" : "Reset", bus, target, lun, 172041962Smjacob ccb.ccb_h.status & CAM_STATUS_MASK); 172139214Sgibbs return(1); 172239214Sgibbs } 172339214Sgibbs} 172439214Sgibbs 172589471Sjoerg#ifndef MINIMALISTIC 172639214Sgibbsstatic int 172739214Sgibbsreaddefects(struct cam_device *device, int argc, char **argv, 172839214Sgibbs char *combinedopt, int retry_count, int timeout) 172939214Sgibbs{ 173039214Sgibbs union ccb *ccb = NULL; 173139214Sgibbs struct scsi_read_defect_data_10 *rdd_cdb; 173239214Sgibbs u_int8_t *defect_list = NULL; 173339214Sgibbs u_int32_t dlist_length = 65000; 173439214Sgibbs u_int32_t returned_length = 0; 173539214Sgibbs u_int32_t num_returned = 0; 173639214Sgibbs u_int8_t returned_format; 1737102192Sjohan unsigned int i; 173839214Sgibbs int c, error = 0; 173939214Sgibbs int lists_specified = 0; 174039214Sgibbs 174139214Sgibbs while ((c = getopt(argc, argv, combinedopt)) != -1) { 174239214Sgibbs switch(c){ 174339214Sgibbs case 'f': 174439214Sgibbs { 174539214Sgibbs char *tstr; 174639214Sgibbs tstr = optarg; 174739214Sgibbs while (isspace(*tstr) && (*tstr != '\0')) 174839214Sgibbs tstr++; 174939214Sgibbs if (strcmp(tstr, "block") == 0) 175039214Sgibbs arglist |= CAM_ARG_FORMAT_BLOCK; 175139214Sgibbs else if (strcmp(tstr, "bfi") == 0) 175239214Sgibbs arglist |= CAM_ARG_FORMAT_BFI; 175339214Sgibbs else if (strcmp(tstr, "phys") == 0) 175439214Sgibbs arglist |= CAM_ARG_FORMAT_PHYS; 175539214Sgibbs else { 175639214Sgibbs error = 1; 175739214Sgibbs warnx("invalid defect format %s", tstr); 175839214Sgibbs goto defect_bailout; 175939214Sgibbs } 176039214Sgibbs break; 176139214Sgibbs } 176239214Sgibbs case 'G': 176339214Sgibbs arglist |= CAM_ARG_GLIST; 176439214Sgibbs break; 176539214Sgibbs case 'P': 176639214Sgibbs arglist |= CAM_ARG_PLIST; 176739214Sgibbs break; 176839214Sgibbs default: 176939214Sgibbs break; 177039214Sgibbs } 177139214Sgibbs } 177239214Sgibbs 177339214Sgibbs ccb = cam_getccb(device); 177439214Sgibbs 177539214Sgibbs /* 177639214Sgibbs * Hopefully 65000 bytes is enough to hold the defect list. If it 177739214Sgibbs * isn't, the disk is probably dead already. We'd have to go with 177839214Sgibbs * 12 byte command (i.e. alloc_length is 32 bits instead of 16) 177939214Sgibbs * to hold them all. 178039214Sgibbs */ 178139214Sgibbs defect_list = malloc(dlist_length); 178269471Sjedgar if (defect_list == NULL) { 178369471Sjedgar warnx("can't malloc memory for defect list"); 178469471Sjedgar error = 1; 178569471Sjedgar goto defect_bailout; 178669471Sjedgar } 178739214Sgibbs 178839214Sgibbs rdd_cdb =(struct scsi_read_defect_data_10 *)&ccb->csio.cdb_io.cdb_bytes; 178939214Sgibbs 179039214Sgibbs /* 179139214Sgibbs * cam_getccb() zeros the CCB header only. So we need to zero the 179239214Sgibbs * payload portion of the ccb. 179339214Sgibbs */ 179446581Sken bzero(&(&ccb->ccb_h)[1], 179546581Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 179639214Sgibbs 179739214Sgibbs cam_fill_csio(&ccb->csio, 179839214Sgibbs /*retries*/ retry_count, 179939214Sgibbs /*cbfcnp*/ NULL, 180051723Sken /*flags*/ CAM_DIR_IN | ((arglist & CAM_ARG_ERR_RECOVER) ? 180151723Sken CAM_PASS_ERR_RECOVER : 0), 180239214Sgibbs /*tag_action*/ MSG_SIMPLE_Q_TAG, 180339214Sgibbs /*data_ptr*/ defect_list, 180439214Sgibbs /*dxfer_len*/ dlist_length, 180539214Sgibbs /*sense_len*/ SSD_FULL_SIZE, 180639214Sgibbs /*cdb_len*/ sizeof(struct scsi_read_defect_data_10), 180739214Sgibbs /*timeout*/ timeout ? timeout : 5000); 180839214Sgibbs 180939214Sgibbs rdd_cdb->opcode = READ_DEFECT_DATA_10; 181039214Sgibbs if (arglist & CAM_ARG_FORMAT_BLOCK) 181139214Sgibbs rdd_cdb->format = SRDD10_BLOCK_FORMAT; 181239214Sgibbs else if (arglist & CAM_ARG_FORMAT_BFI) 181339214Sgibbs rdd_cdb->format = SRDD10_BYTES_FROM_INDEX_FORMAT; 181439214Sgibbs else if (arglist & CAM_ARG_FORMAT_PHYS) 181539214Sgibbs rdd_cdb->format = SRDD10_PHYSICAL_SECTOR_FORMAT; 181639214Sgibbs else { 181739214Sgibbs error = 1; 181839214Sgibbs warnx("no defect list format specified"); 181939214Sgibbs goto defect_bailout; 182039214Sgibbs } 182139214Sgibbs if (arglist & CAM_ARG_PLIST) { 182239214Sgibbs rdd_cdb->format |= SRDD10_PLIST; 182339214Sgibbs lists_specified++; 182439214Sgibbs } 182539214Sgibbs 182639214Sgibbs if (arglist & CAM_ARG_GLIST) { 182739214Sgibbs rdd_cdb->format |= SRDD10_GLIST; 182839214Sgibbs lists_specified++; 182939214Sgibbs } 183039214Sgibbs 183139214Sgibbs scsi_ulto2b(dlist_length, rdd_cdb->alloc_length); 183239214Sgibbs 183339214Sgibbs /* Disable freezing the device queue */ 183439214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 183539214Sgibbs 183639214Sgibbs if (cam_send_ccb(device, ccb) < 0) { 183739214Sgibbs perror("error reading defect list"); 183839214Sgibbs 183939214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 184074840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 184174840Sken CAM_EPF_ALL, stderr); 184239214Sgibbs } 184339214Sgibbs 184439214Sgibbs error = 1; 184539214Sgibbs goto defect_bailout; 184639214Sgibbs } 184739214Sgibbs 184839214Sgibbs returned_length = scsi_2btoul(((struct 184939214Sgibbs scsi_read_defect_data_hdr_10 *)defect_list)->length); 185039214Sgibbs 185139214Sgibbs returned_format = ((struct scsi_read_defect_data_hdr_10 *) 185239214Sgibbs defect_list)->format; 185339214Sgibbs 185474840Sken if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) 185574840Sken && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) 185674840Sken && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) { 185739214Sgibbs struct scsi_sense_data *sense; 185839214Sgibbs int error_code, sense_key, asc, ascq; 185939214Sgibbs 186039214Sgibbs sense = &ccb->csio.sense_data; 186139214Sgibbs scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq); 186239214Sgibbs 186339214Sgibbs /* 186439214Sgibbs * According to the SCSI spec, if the disk doesn't support 186539214Sgibbs * the requested format, it will generally return a sense 186639214Sgibbs * key of RECOVERED ERROR, and an additional sense code 186739214Sgibbs * of "DEFECT LIST NOT FOUND". So, we check for that, and 186839214Sgibbs * also check to make sure that the returned length is 186939214Sgibbs * greater than 0, and then print out whatever format the 187039214Sgibbs * disk gave us. 187139214Sgibbs */ 187239214Sgibbs if ((sense_key == SSD_KEY_RECOVERED_ERROR) 187339214Sgibbs && (asc == 0x1c) && (ascq == 0x00) 187439214Sgibbs && (returned_length > 0)) { 187539214Sgibbs warnx("requested defect format not available"); 187639214Sgibbs switch(returned_format & SRDDH10_DLIST_FORMAT_MASK) { 187739214Sgibbs case SRDD10_BLOCK_FORMAT: 187839214Sgibbs warnx("Device returned block format"); 187939214Sgibbs break; 188039214Sgibbs case SRDD10_BYTES_FROM_INDEX_FORMAT: 188139214Sgibbs warnx("Device returned bytes from index" 188239214Sgibbs " format"); 188339214Sgibbs break; 188439214Sgibbs case SRDD10_PHYSICAL_SECTOR_FORMAT: 188539214Sgibbs warnx("Device returned physical sector format"); 188639214Sgibbs break; 188739214Sgibbs default: 188839214Sgibbs error = 1; 188939214Sgibbs warnx("Device returned unknown defect" 189039214Sgibbs " data format %#x", returned_format); 189139214Sgibbs goto defect_bailout; 189239214Sgibbs break; /* NOTREACHED */ 189339214Sgibbs } 189439214Sgibbs } else { 189539214Sgibbs error = 1; 189639214Sgibbs warnx("Error returned from read defect data command"); 189774840Sken if (arglist & CAM_ARG_VERBOSE) 189874840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 189974840Sken CAM_EPF_ALL, stderr); 190039214Sgibbs goto defect_bailout; 190139214Sgibbs } 190287378Sken } else if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 190374840Sken error = 1; 190474840Sken warnx("Error returned from read defect data command"); 190574840Sken if (arglist & CAM_ARG_VERBOSE) 190674840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 190774840Sken CAM_EPF_ALL, stderr); 190874840Sken goto defect_bailout; 190939214Sgibbs } 191039214Sgibbs 191139214Sgibbs /* 191239214Sgibbs * XXX KDM I should probably clean up the printout format for the 1913214321Smav * disk defects. 191439214Sgibbs */ 191539214Sgibbs switch (returned_format & SRDDH10_DLIST_FORMAT_MASK){ 191639214Sgibbs case SRDDH10_PHYSICAL_SECTOR_FORMAT: 191739214Sgibbs { 191839214Sgibbs struct scsi_defect_desc_phys_sector *dlist; 191939214Sgibbs 192039214Sgibbs dlist = (struct scsi_defect_desc_phys_sector *) 192139214Sgibbs (defect_list + 192239214Sgibbs sizeof(struct scsi_read_defect_data_hdr_10)); 192339214Sgibbs 192439214Sgibbs num_returned = returned_length / 192539214Sgibbs sizeof(struct scsi_defect_desc_phys_sector); 192639214Sgibbs 192739214Sgibbs fprintf(stderr, "Got %d defect", num_returned); 192839214Sgibbs 192939214Sgibbs if ((lists_specified == 0) || (num_returned == 0)) { 193039214Sgibbs fprintf(stderr, "s.\n"); 193139214Sgibbs break; 193239214Sgibbs } else if (num_returned == 1) 193339214Sgibbs fprintf(stderr, ":\n"); 193439214Sgibbs else 193539214Sgibbs fprintf(stderr, "s:\n"); 193639214Sgibbs 193739214Sgibbs for (i = 0; i < num_returned; i++) { 193839214Sgibbs fprintf(stdout, "%d:%d:%d\n", 193939214Sgibbs scsi_3btoul(dlist[i].cylinder), 194039214Sgibbs dlist[i].head, 194139214Sgibbs scsi_4btoul(dlist[i].sector)); 194239214Sgibbs } 194339214Sgibbs break; 194439214Sgibbs } 194539214Sgibbs case SRDDH10_BYTES_FROM_INDEX_FORMAT: 194639214Sgibbs { 194739214Sgibbs struct scsi_defect_desc_bytes_from_index *dlist; 194839214Sgibbs 194939214Sgibbs dlist = (struct scsi_defect_desc_bytes_from_index *) 195039214Sgibbs (defect_list + 195139214Sgibbs sizeof(struct scsi_read_defect_data_hdr_10)); 195239214Sgibbs 195339214Sgibbs num_returned = returned_length / 195439214Sgibbs sizeof(struct scsi_defect_desc_bytes_from_index); 195539214Sgibbs 195639214Sgibbs fprintf(stderr, "Got %d defect", num_returned); 195739214Sgibbs 195839214Sgibbs if ((lists_specified == 0) || (num_returned == 0)) { 195939214Sgibbs fprintf(stderr, "s.\n"); 196039214Sgibbs break; 196139214Sgibbs } else if (num_returned == 1) 196239214Sgibbs fprintf(stderr, ":\n"); 196339214Sgibbs else 196439214Sgibbs fprintf(stderr, "s:\n"); 196539214Sgibbs 196639214Sgibbs for (i = 0; i < num_returned; i++) { 196739214Sgibbs fprintf(stdout, "%d:%d:%d\n", 196839214Sgibbs scsi_3btoul(dlist[i].cylinder), 196939214Sgibbs dlist[i].head, 197039214Sgibbs scsi_4btoul(dlist[i].bytes_from_index)); 197139214Sgibbs } 197239214Sgibbs break; 197339214Sgibbs } 197439214Sgibbs case SRDDH10_BLOCK_FORMAT: 197539214Sgibbs { 197639214Sgibbs struct scsi_defect_desc_block *dlist; 197739214Sgibbs 197839214Sgibbs dlist = (struct scsi_defect_desc_block *)(defect_list + 197939214Sgibbs sizeof(struct scsi_read_defect_data_hdr_10)); 198039214Sgibbs 198139214Sgibbs num_returned = returned_length / 198239214Sgibbs sizeof(struct scsi_defect_desc_block); 198339214Sgibbs 198439214Sgibbs fprintf(stderr, "Got %d defect", num_returned); 198539214Sgibbs 198639214Sgibbs if ((lists_specified == 0) || (num_returned == 0)) { 198739214Sgibbs fprintf(stderr, "s.\n"); 198839214Sgibbs break; 198939214Sgibbs } else if (num_returned == 1) 199039214Sgibbs fprintf(stderr, ":\n"); 199139214Sgibbs else 199239214Sgibbs fprintf(stderr, "s:\n"); 199339214Sgibbs 199439214Sgibbs for (i = 0; i < num_returned; i++) 199539214Sgibbs fprintf(stdout, "%u\n", 199639214Sgibbs scsi_4btoul(dlist[i].address)); 199739214Sgibbs break; 199839214Sgibbs } 199939214Sgibbs default: 200039214Sgibbs fprintf(stderr, "Unknown defect format %d\n", 200139214Sgibbs returned_format & SRDDH10_DLIST_FORMAT_MASK); 200239214Sgibbs error = 1; 200339214Sgibbs break; 200439214Sgibbs } 200539214Sgibbsdefect_bailout: 200639214Sgibbs 200739214Sgibbs if (defect_list != NULL) 200839214Sgibbs free(defect_list); 200939214Sgibbs 201039214Sgibbs if (ccb != NULL) 201139214Sgibbs cam_freeccb(ccb); 201239214Sgibbs 201339214Sgibbs return(error); 201439214Sgibbs} 201589471Sjoerg#endif /* MINIMALISTIC */ 201639214Sgibbs 201739214Sgibbs#if 0 201839214Sgibbsvoid 201939214Sgibbsreassignblocks(struct cam_device *device, u_int32_t *blocks, int num_blocks) 202039214Sgibbs{ 202139214Sgibbs union ccb *ccb; 2022214321Smav 202339214Sgibbs ccb = cam_getccb(device); 202439214Sgibbs 202539214Sgibbs cam_freeccb(ccb); 202639214Sgibbs} 202739214Sgibbs#endif 202839214Sgibbs 202989471Sjoerg#ifndef MINIMALISTIC 203039214Sgibbsvoid 203139214Sgibbsmode_sense(struct cam_device *device, int mode_page, int page_control, 203239214Sgibbs int dbd, int retry_count, int timeout, u_int8_t *data, int datalen) 203339214Sgibbs{ 203439214Sgibbs union ccb *ccb; 203539214Sgibbs int retval; 203639214Sgibbs 203739214Sgibbs ccb = cam_getccb(device); 203839214Sgibbs 203939214Sgibbs if (ccb == NULL) 204039214Sgibbs errx(1, "mode_sense: couldn't allocate CCB"); 204139214Sgibbs 204246581Sken bzero(&(&ccb->ccb_h)[1], 204346581Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 204439214Sgibbs 204539214Sgibbs scsi_mode_sense(&ccb->csio, 204639214Sgibbs /* retries */ retry_count, 204739214Sgibbs /* cbfcnp */ NULL, 204839214Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 204939214Sgibbs /* dbd */ dbd, 205039214Sgibbs /* page_code */ page_control << 6, 205139214Sgibbs /* page */ mode_page, 205239214Sgibbs /* param_buf */ data, 205339214Sgibbs /* param_len */ datalen, 205439214Sgibbs /* sense_len */ SSD_FULL_SIZE, 205539214Sgibbs /* timeout */ timeout ? timeout : 5000); 205639214Sgibbs 205739214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 205839214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 205939214Sgibbs 206039214Sgibbs /* Disable freezing the device queue */ 206139214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 206239214Sgibbs 206339214Sgibbs if (((retval = cam_send_ccb(device, ccb)) < 0) 206439214Sgibbs || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 206539214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 206674840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 206774840Sken CAM_EPF_ALL, stderr); 206839214Sgibbs } 206939214Sgibbs cam_freeccb(ccb); 207039214Sgibbs cam_close_device(device); 207139214Sgibbs if (retval < 0) 207239214Sgibbs err(1, "error sending mode sense command"); 207339214Sgibbs else 207439214Sgibbs errx(1, "error sending mode sense command"); 207539214Sgibbs } 207639214Sgibbs 207739214Sgibbs cam_freeccb(ccb); 207839214Sgibbs} 207939214Sgibbs 208039214Sgibbsvoid 208139214Sgibbsmode_select(struct cam_device *device, int save_pages, int retry_count, 208239214Sgibbs int timeout, u_int8_t *data, int datalen) 208339214Sgibbs{ 208439214Sgibbs union ccb *ccb; 208539214Sgibbs int retval; 208639214Sgibbs 208739214Sgibbs ccb = cam_getccb(device); 208839214Sgibbs 208939214Sgibbs if (ccb == NULL) 209039214Sgibbs errx(1, "mode_select: couldn't allocate CCB"); 209139214Sgibbs 209246581Sken bzero(&(&ccb->ccb_h)[1], 209346581Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 209439214Sgibbs 209539214Sgibbs scsi_mode_select(&ccb->csio, 209639214Sgibbs /* retries */ retry_count, 209739214Sgibbs /* cbfcnp */ NULL, 209839214Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 209939214Sgibbs /* scsi_page_fmt */ 1, 210039214Sgibbs /* save_pages */ save_pages, 210139214Sgibbs /* param_buf */ data, 210239214Sgibbs /* param_len */ datalen, 210339214Sgibbs /* sense_len */ SSD_FULL_SIZE, 210439214Sgibbs /* timeout */ timeout ? timeout : 5000); 210539214Sgibbs 210639214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 210739214Sgibbs ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 210839214Sgibbs 210939214Sgibbs /* Disable freezing the device queue */ 211039214Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 211139214Sgibbs 211239214Sgibbs if (((retval = cam_send_ccb(device, ccb)) < 0) 211339214Sgibbs || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 211439214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 211574840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 211674840Sken CAM_EPF_ALL, stderr); 211739214Sgibbs } 211839214Sgibbs cam_freeccb(ccb); 211939214Sgibbs cam_close_device(device); 212039214Sgibbs 212139214Sgibbs if (retval < 0) 212239214Sgibbs err(1, "error sending mode select command"); 212339214Sgibbs else 212439214Sgibbs errx(1, "error sending mode select command"); 2125214321Smav 212639214Sgibbs } 212739214Sgibbs 212839214Sgibbs cam_freeccb(ccb); 212939214Sgibbs} 213039214Sgibbs 213139214Sgibbsvoid 213239214Sgibbsmodepage(struct cam_device *device, int argc, char **argv, char *combinedopt, 213339214Sgibbs int retry_count, int timeout) 213439214Sgibbs{ 213539214Sgibbs int c, mode_page = -1, page_control = 0; 213664382Skbyanc int binary = 0, list = 0; 213739214Sgibbs 213839214Sgibbs while ((c = getopt(argc, argv, combinedopt)) != -1) { 213939214Sgibbs switch(c) { 214064382Skbyanc case 'b': 214164382Skbyanc binary = 1; 214264382Skbyanc break; 214339214Sgibbs case 'd': 214439214Sgibbs arglist |= CAM_ARG_DBD; 214539214Sgibbs break; 214639214Sgibbs case 'e': 214739214Sgibbs arglist |= CAM_ARG_MODE_EDIT; 214839214Sgibbs break; 214964382Skbyanc case 'l': 215064382Skbyanc list = 1; 215164382Skbyanc break; 215239214Sgibbs case 'm': 215339214Sgibbs mode_page = strtol(optarg, NULL, 0); 215439214Sgibbs if (mode_page < 0) 215539214Sgibbs errx(1, "invalid mode page %d", mode_page); 215639214Sgibbs break; 215739214Sgibbs case 'P': 215839214Sgibbs page_control = strtol(optarg, NULL, 0); 215939214Sgibbs if ((page_control < 0) || (page_control > 3)) 216039214Sgibbs errx(1, "invalid page control field %d", 216139214Sgibbs page_control); 216239214Sgibbs arglist |= CAM_ARG_PAGE_CNTL; 216339214Sgibbs break; 216439214Sgibbs default: 216539214Sgibbs break; 216639214Sgibbs } 216739214Sgibbs } 216839214Sgibbs 216964382Skbyanc if (mode_page == -1 && list == 0) 217039214Sgibbs errx(1, "you must specify a mode page!"); 217139214Sgibbs 217264382Skbyanc if (list) { 217364382Skbyanc mode_list(device, page_control, arglist & CAM_ARG_DBD, 217464382Skbyanc retry_count, timeout); 217564382Skbyanc } else { 217664382Skbyanc mode_edit(device, mode_page, page_control, 217764382Skbyanc arglist & CAM_ARG_DBD, arglist & CAM_ARG_MODE_EDIT, binary, 217864382Skbyanc retry_count, timeout); 217964382Skbyanc } 218039214Sgibbs} 218139214Sgibbs 218239214Sgibbsstatic int 218339214Sgibbsscsicmd(struct cam_device *device, int argc, char **argv, char *combinedopt, 218439214Sgibbs int retry_count, int timeout) 218539214Sgibbs{ 218639214Sgibbs union ccb *ccb; 218739214Sgibbs u_int32_t flags = CAM_DIR_NONE; 218839214Sgibbs u_int8_t *data_ptr = NULL; 218939214Sgibbs u_int8_t cdb[20]; 2190196831Smav u_int8_t atacmd[12]; 219139214Sgibbs struct get_hook hook; 219239214Sgibbs int c, data_bytes = 0; 219339214Sgibbs int cdb_len = 0; 2194196831Smav int atacmd_len = 0; 2195207498Smav int dmacmd = 0; 2196207498Smav int fpdmacmd = 0; 2197196831Smav int need_res = 0; 2198196831Smav char *datastr = NULL, *tstr, *resstr = NULL; 219939214Sgibbs int error = 0; 2200196831Smav int fd_data = 0, fd_res = 0; 220139214Sgibbs int retval; 220239214Sgibbs 220339214Sgibbs ccb = cam_getccb(device); 220439214Sgibbs 220539214Sgibbs if (ccb == NULL) { 220639214Sgibbs warnx("scsicmd: error allocating ccb"); 220739214Sgibbs return(1); 220839214Sgibbs } 220939214Sgibbs 221046581Sken bzero(&(&ccb->ccb_h)[1], 2211196831Smav sizeof(union ccb) - sizeof(struct ccb_hdr)); 221239214Sgibbs 221339214Sgibbs while ((c = getopt(argc, argv, combinedopt)) != -1) { 221439214Sgibbs switch(c) { 2215196831Smav case 'a': 2216196831Smav tstr = optarg; 2217196831Smav while (isspace(*tstr) && (*tstr != '\0')) 2218196831Smav tstr++; 2219196831Smav hook.argc = argc - optind; 2220196831Smav hook.argv = argv + optind; 2221196831Smav hook.got = 0; 2222196831Smav atacmd_len = buff_encode_visit(atacmd, sizeof(atacmd), tstr, 2223196831Smav iget, &hook); 2224196831Smav /* 2225196831Smav * Increment optind by the number of arguments the 2226196831Smav * encoding routine processed. After each call to 2227196831Smav * getopt(3), optind points to the argument that 2228196831Smav * getopt should process _next_. In this case, 2229196831Smav * that means it points to the first command string 2230196831Smav * argument, if there is one. Once we increment 2231196831Smav * this, it should point to either the next command 2232196831Smav * line argument, or it should be past the end of 2233196831Smav * the list. 2234196831Smav */ 2235196831Smav optind += hook.got; 2236196831Smav break; 223739214Sgibbs case 'c': 223839214Sgibbs tstr = optarg; 223939214Sgibbs while (isspace(*tstr) && (*tstr != '\0')) 224039214Sgibbs tstr++; 224139214Sgibbs hook.argc = argc - optind; 224239214Sgibbs hook.argv = argv + optind; 224339214Sgibbs hook.got = 0; 224447867Sken cdb_len = buff_encode_visit(cdb, sizeof(cdb), tstr, 224547867Sken iget, &hook); 224639214Sgibbs /* 224739214Sgibbs * Increment optind by the number of arguments the 224839214Sgibbs * encoding routine processed. After each call to 224939214Sgibbs * getopt(3), optind points to the argument that 225039214Sgibbs * getopt should process _next_. In this case, 225139214Sgibbs * that means it points to the first command string 225239214Sgibbs * argument, if there is one. Once we increment 225339214Sgibbs * this, it should point to either the next command 225439214Sgibbs * line argument, or it should be past the end of 225539214Sgibbs * the list. 225639214Sgibbs */ 225739214Sgibbs optind += hook.got; 225839214Sgibbs break; 2259207498Smav case 'd': 2260207498Smav dmacmd = 1; 2261207498Smav break; 2262207498Smav case 'f': 2263207498Smav fpdmacmd = 1; 2264207498Smav break; 226539214Sgibbs case 'i': 226639214Sgibbs if (arglist & CAM_ARG_CMD_OUT) { 226739214Sgibbs warnx("command must either be " 226839214Sgibbs "read or write, not both"); 226939214Sgibbs error = 1; 227039214Sgibbs goto scsicmd_bailout; 227139214Sgibbs } 227239214Sgibbs arglist |= CAM_ARG_CMD_IN; 227339214Sgibbs flags = CAM_DIR_IN; 227439214Sgibbs data_bytes = strtol(optarg, NULL, 0); 227539214Sgibbs if (data_bytes <= 0) { 227639214Sgibbs warnx("invalid number of input bytes %d", 227739214Sgibbs data_bytes); 227839214Sgibbs error = 1; 227939214Sgibbs goto scsicmd_bailout; 228039214Sgibbs } 228139214Sgibbs hook.argc = argc - optind; 228239214Sgibbs hook.argv = argv + optind; 228339214Sgibbs hook.got = 0; 228439214Sgibbs optind++; 228539214Sgibbs datastr = cget(&hook, NULL); 228639214Sgibbs /* 228739214Sgibbs * If the user supplied "-" instead of a format, he 228839214Sgibbs * wants the data to be written to stdout. 228939214Sgibbs */ 229039214Sgibbs if ((datastr != NULL) 229139214Sgibbs && (datastr[0] == '-')) 229239214Sgibbs fd_data = 1; 229339214Sgibbs 229439214Sgibbs data_ptr = (u_int8_t *)malloc(data_bytes); 229569471Sjedgar if (data_ptr == NULL) { 229669471Sjedgar warnx("can't malloc memory for data_ptr"); 229769471Sjedgar error = 1; 229869471Sjedgar goto scsicmd_bailout; 229969471Sjedgar } 230039214Sgibbs break; 230139214Sgibbs case 'o': 230239214Sgibbs if (arglist & CAM_ARG_CMD_IN) { 230339214Sgibbs warnx("command must either be " 230439214Sgibbs "read or write, not both"); 2305214321Smav error = 1; 230639214Sgibbs goto scsicmd_bailout; 230739214Sgibbs } 230839214Sgibbs arglist |= CAM_ARG_CMD_OUT; 230939214Sgibbs flags = CAM_DIR_OUT; 231039214Sgibbs data_bytes = strtol(optarg, NULL, 0); 231139214Sgibbs if (data_bytes <= 0) { 231239214Sgibbs warnx("invalid number of output bytes %d", 231339214Sgibbs data_bytes); 231439214Sgibbs error = 1; 231539214Sgibbs goto scsicmd_bailout; 231639214Sgibbs } 231739214Sgibbs hook.argc = argc - optind; 231839214Sgibbs hook.argv = argv + optind; 231939214Sgibbs hook.got = 0; 232039214Sgibbs datastr = cget(&hook, NULL); 232139214Sgibbs data_ptr = (u_int8_t *)malloc(data_bytes); 232269471Sjedgar if (data_ptr == NULL) { 232369471Sjedgar warnx("can't malloc memory for data_ptr"); 232469471Sjedgar error = 1; 232569471Sjedgar goto scsicmd_bailout; 232669471Sjedgar } 2327202694Smav bzero(data_ptr, data_bytes); 232839214Sgibbs /* 232939214Sgibbs * If the user supplied "-" instead of a format, he 233039214Sgibbs * wants the data to be read from stdin. 233139214Sgibbs */ 233239214Sgibbs if ((datastr != NULL) 233339214Sgibbs && (datastr[0] == '-')) 233439214Sgibbs fd_data = 1; 233539214Sgibbs else 233639214Sgibbs buff_encode_visit(data_ptr, data_bytes, datastr, 233739214Sgibbs iget, &hook); 233839214Sgibbs optind += hook.got; 233939214Sgibbs break; 2340196831Smav case 'r': 2341196831Smav need_res = 1; 2342196831Smav hook.argc = argc - optind; 2343196831Smav hook.argv = argv + optind; 2344196831Smav hook.got = 0; 2345196831Smav resstr = cget(&hook, NULL); 2346196831Smav if ((resstr != NULL) && (resstr[0] == '-')) 2347196831Smav fd_res = 1; 2348196831Smav optind += hook.got; 2349196831Smav break; 235039214Sgibbs default: 235139214Sgibbs break; 235239214Sgibbs } 235339214Sgibbs } 235439214Sgibbs 235539214Sgibbs /* 235639214Sgibbs * If fd_data is set, and we're writing to the device, we need to 235739214Sgibbs * read the data the user wants written from stdin. 235839214Sgibbs */ 235939214Sgibbs if ((fd_data == 1) && (arglist & CAM_ARG_CMD_OUT)) { 2360102192Sjohan ssize_t amt_read; 236139214Sgibbs int amt_to_read = data_bytes; 236239214Sgibbs u_int8_t *buf_ptr = data_ptr; 236339214Sgibbs 236439214Sgibbs for (amt_read = 0; amt_to_read > 0; 236580381Ssheldonh amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) { 236639214Sgibbs if (amt_read == -1) { 236739214Sgibbs warn("error reading data from stdin"); 236839214Sgibbs error = 1; 236939214Sgibbs goto scsicmd_bailout; 237039214Sgibbs } 237139214Sgibbs amt_to_read -= amt_read; 237239214Sgibbs buf_ptr += amt_read; 237339214Sgibbs } 237439214Sgibbs } 237539214Sgibbs 237639214Sgibbs if (arglist & CAM_ARG_ERR_RECOVER) 237739214Sgibbs flags |= CAM_PASS_ERR_RECOVER; 237839214Sgibbs 237939214Sgibbs /* Disable freezing the device queue */ 238039214Sgibbs flags |= CAM_DEV_QFRZDIS; 238139214Sgibbs 2382196831Smav if (cdb_len) { 2383196831Smav /* 2384196831Smav * This is taken from the SCSI-3 draft spec. 2385196831Smav * (T10/1157D revision 0.3) 2386196831Smav * The top 3 bits of an opcode are the group code. 2387196831Smav * The next 5 bits are the command code. 2388196831Smav * Group 0: six byte commands 2389196831Smav * Group 1: ten byte commands 2390196831Smav * Group 2: ten byte commands 2391196831Smav * Group 3: reserved 2392196831Smav * Group 4: sixteen byte commands 2393196831Smav * Group 5: twelve byte commands 2394196831Smav * Group 6: vendor specific 2395196831Smav * Group 7: vendor specific 2396196831Smav */ 2397196831Smav switch((cdb[0] >> 5) & 0x7) { 2398196831Smav case 0: 2399196831Smav cdb_len = 6; 2400196831Smav break; 2401196831Smav case 1: 2402196831Smav case 2: 2403196831Smav cdb_len = 10; 2404196831Smav break; 2405196831Smav case 3: 2406196831Smav case 6: 2407196831Smav case 7: 2408196831Smav /* computed by buff_encode_visit */ 2409196831Smav break; 2410196831Smav case 4: 2411196831Smav cdb_len = 16; 2412196831Smav break; 2413196831Smav case 5: 2414196831Smav cdb_len = 12; 2415196831Smav break; 2416196831Smav } 241739214Sgibbs 2418196831Smav /* 2419196831Smav * We should probably use csio_build_visit or something like that 2420196831Smav * here, but it's easier to encode arguments as you go. The 2421196831Smav * alternative would be skipping the CDB argument and then encoding 2422196831Smav * it here, since we've got the data buffer argument by now. 2423196831Smav */ 2424196831Smav bcopy(cdb, &ccb->csio.cdb_io.cdb_bytes, cdb_len); 242539214Sgibbs 2426196831Smav cam_fill_csio(&ccb->csio, 242739214Sgibbs /*retries*/ retry_count, 242839214Sgibbs /*cbfcnp*/ NULL, 242939214Sgibbs /*flags*/ flags, 243039214Sgibbs /*tag_action*/ MSG_SIMPLE_Q_TAG, 243139214Sgibbs /*data_ptr*/ data_ptr, 243239214Sgibbs /*dxfer_len*/ data_bytes, 243339214Sgibbs /*sense_len*/ SSD_FULL_SIZE, 243439214Sgibbs /*cdb_len*/ cdb_len, 243539214Sgibbs /*timeout*/ timeout ? timeout : 5000); 2436196831Smav } else { 2437196831Smav atacmd_len = 12; 2438196831Smav bcopy(atacmd, &ccb->ataio.cmd.command, atacmd_len); 2439196831Smav if (need_res) 2440196831Smav ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT; 2441207498Smav if (dmacmd) 2442207498Smav ccb->ataio.cmd.flags |= CAM_ATAIO_DMA; 2443207498Smav if (fpdmacmd) 2444207498Smav ccb->ataio.cmd.flags |= CAM_ATAIO_FPDMA; 244539214Sgibbs 2446196831Smav cam_fill_ataio(&ccb->ataio, 2447196831Smav /*retries*/ retry_count, 2448196831Smav /*cbfcnp*/ NULL, 2449196831Smav /*flags*/ flags, 2450196831Smav /*tag_action*/ 0, 2451196831Smav /*data_ptr*/ data_ptr, 2452196831Smav /*dxfer_len*/ data_bytes, 2453196831Smav /*timeout*/ timeout ? timeout : 5000); 2454196831Smav } 2455196831Smav 245639214Sgibbs if (((retval = cam_send_ccb(device, ccb)) < 0) 245739214Sgibbs || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 245839214Sgibbs if (retval < 0) 245939214Sgibbs warn("error sending command"); 246039214Sgibbs else 246139214Sgibbs warnx("error sending command"); 246239214Sgibbs 246339214Sgibbs if (arglist & CAM_ARG_VERBOSE) { 246474840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 246574840Sken CAM_EPF_ALL, stderr); 246639214Sgibbs } 246739214Sgibbs 246839214Sgibbs error = 1; 246939214Sgibbs goto scsicmd_bailout; 247039214Sgibbs } 247139214Sgibbs 2472196831Smav if (atacmd_len && need_res) { 2473196831Smav if (fd_res == 0) { 2474196831Smav buff_decode_visit(&ccb->ataio.res.status, 11, resstr, 2475196831Smav arg_put, NULL); 2476196831Smav fprintf(stdout, "\n"); 2477196831Smav } else { 2478196831Smav fprintf(stdout, 2479196831Smav "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", 2480196831Smav ccb->ataio.res.status, 2481196831Smav ccb->ataio.res.error, 2482196831Smav ccb->ataio.res.lba_low, 2483196831Smav ccb->ataio.res.lba_mid, 2484196831Smav ccb->ataio.res.lba_high, 2485196831Smav ccb->ataio.res.device, 2486196831Smav ccb->ataio.res.lba_low_exp, 2487196831Smav ccb->ataio.res.lba_mid_exp, 2488196831Smav ccb->ataio.res.lba_high_exp, 2489196831Smav ccb->ataio.res.sector_count, 2490196831Smav ccb->ataio.res.sector_count_exp); 2491196831Smav fflush(stdout); 2492196831Smav } 2493196831Smav } 249439214Sgibbs 249539214Sgibbs if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 249639214Sgibbs && (arglist & CAM_ARG_CMD_IN) 249739214Sgibbs && (data_bytes > 0)) { 249839214Sgibbs if (fd_data == 0) { 249939214Sgibbs buff_decode_visit(data_ptr, data_bytes, datastr, 250039214Sgibbs arg_put, NULL); 250139214Sgibbs fprintf(stdout, "\n"); 250239214Sgibbs } else { 2503102192Sjohan ssize_t amt_written; 250439214Sgibbs int amt_to_write = data_bytes; 250539214Sgibbs u_int8_t *buf_ptr = data_ptr; 250639214Sgibbs 250739214Sgibbs for (amt_written = 0; (amt_to_write > 0) && 250839214Sgibbs (amt_written =write(1, buf_ptr,amt_to_write))> 0;){ 250939214Sgibbs amt_to_write -= amt_written; 251039214Sgibbs buf_ptr += amt_written; 251139214Sgibbs } 251239214Sgibbs if (amt_written == -1) { 251339214Sgibbs warn("error writing data to stdout"); 251439214Sgibbs error = 1; 251539214Sgibbs goto scsicmd_bailout; 251639214Sgibbs } else if ((amt_written == 0) 251739214Sgibbs && (amt_to_write > 0)) { 251839214Sgibbs warnx("only wrote %u bytes out of %u", 251939214Sgibbs data_bytes - amt_to_write, data_bytes); 252039214Sgibbs } 252139214Sgibbs } 252239214Sgibbs } 252339214Sgibbs 252439214Sgibbsscsicmd_bailout: 252539214Sgibbs 252639214Sgibbs if ((data_bytes > 0) && (data_ptr != NULL)) 252739214Sgibbs free(data_ptr); 252839214Sgibbs 252939214Sgibbs cam_freeccb(ccb); 253039214Sgibbs 253139214Sgibbs return(error); 253239214Sgibbs} 253339214Sgibbs 253439214Sgibbsstatic int 253539214Sgibbscamdebug(int argc, char **argv, char *combinedopt) 253639214Sgibbs{ 253739214Sgibbs int c, fd; 253839214Sgibbs int bus = -1, target = -1, lun = -1; 253939214Sgibbs char *tstr, *tmpstr = NULL; 254039214Sgibbs union ccb ccb; 254139214Sgibbs int error = 0; 254239214Sgibbs 254339214Sgibbs bzero(&ccb, sizeof(union ccb)); 254439214Sgibbs 254539214Sgibbs while ((c = getopt(argc, argv, combinedopt)) != -1) { 254639214Sgibbs switch(c) { 254739214Sgibbs case 'I': 254839214Sgibbs arglist |= CAM_ARG_DEBUG_INFO; 254939214Sgibbs ccb.cdbg.flags |= CAM_DEBUG_INFO; 255039214Sgibbs break; 2551107966Snjl case 'P': 2552107966Snjl arglist |= CAM_ARG_DEBUG_PERIPH; 2553107966Snjl ccb.cdbg.flags |= CAM_DEBUG_PERIPH; 2554107966Snjl break; 255552541Sluoqi case 'S': 255652541Sluoqi arglist |= CAM_ARG_DEBUG_SUBTRACE; 255752541Sluoqi ccb.cdbg.flags |= CAM_DEBUG_SUBTRACE; 255852541Sluoqi break; 255952535Sluoqi case 'T': 256039214Sgibbs arglist |= CAM_ARG_DEBUG_TRACE; 256139214Sgibbs ccb.cdbg.flags |= CAM_DEBUG_TRACE; 256239214Sgibbs break; 2563107966Snjl case 'X': 2564107966Snjl arglist |= CAM_ARG_DEBUG_XPT; 2565107966Snjl ccb.cdbg.flags |= CAM_DEBUG_XPT; 2566107966Snjl break; 256739903Sken case 'c': 256839903Sken arglist |= CAM_ARG_DEBUG_CDB; 256939903Sken ccb.cdbg.flags |= CAM_DEBUG_CDB; 257039903Sken break; 257139214Sgibbs default: 257239214Sgibbs break; 257339214Sgibbs } 257439214Sgibbs } 257539214Sgibbs 257639214Sgibbs if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { 257739214Sgibbs warnx("error opening transport layer device %s", XPT_DEVICE); 257839214Sgibbs warn("%s", XPT_DEVICE); 257939214Sgibbs return(1); 258039214Sgibbs } 258139214Sgibbs argc -= optind; 258239214Sgibbs argv += optind; 258339214Sgibbs 258439214Sgibbs if (argc <= 0) { 258539214Sgibbs warnx("you must specify \"off\", \"all\" or a bus,"); 258639214Sgibbs warnx("bus:target, or bus:target:lun"); 258739214Sgibbs close(fd); 258839214Sgibbs return(1); 258939214Sgibbs } 259039214Sgibbs 259139214Sgibbs tstr = *argv; 259239214Sgibbs 259339214Sgibbs while (isspace(*tstr) && (*tstr != '\0')) 259439214Sgibbs tstr++; 259539214Sgibbs 259639214Sgibbs if (strncmp(tstr, "off", 3) == 0) { 259739214Sgibbs ccb.cdbg.flags = CAM_DEBUG_NONE; 2598107966Snjl arglist &= ~(CAM_ARG_DEBUG_INFO|CAM_ARG_DEBUG_PERIPH| 2599107966Snjl CAM_ARG_DEBUG_TRACE|CAM_ARG_DEBUG_SUBTRACE| 2600107966Snjl CAM_ARG_DEBUG_XPT); 260139214Sgibbs } else if (strncmp(tstr, "all", 3) != 0) { 260239214Sgibbs tmpstr = (char *)strtok(tstr, ":"); 260339214Sgibbs if ((tmpstr != NULL) && (*tmpstr != '\0')){ 260439214Sgibbs bus = strtol(tmpstr, NULL, 0); 260539214Sgibbs arglist |= CAM_ARG_BUS; 260639214Sgibbs tmpstr = (char *)strtok(NULL, ":"); 260739214Sgibbs if ((tmpstr != NULL) && (*tmpstr != '\0')){ 260839214Sgibbs target = strtol(tmpstr, NULL, 0); 260939214Sgibbs arglist |= CAM_ARG_TARGET; 261039214Sgibbs tmpstr = (char *)strtok(NULL, ":"); 261139214Sgibbs if ((tmpstr != NULL) && (*tmpstr != '\0')){ 261239214Sgibbs lun = strtol(tmpstr, NULL, 0); 261339214Sgibbs arglist |= CAM_ARG_LUN; 261439214Sgibbs } 261539214Sgibbs } 261639214Sgibbs } else { 261739214Sgibbs error = 1; 261839214Sgibbs warnx("you must specify \"all\", \"off\", or a bus,"); 261939214Sgibbs warnx("bus:target, or bus:target:lun to debug"); 262039214Sgibbs } 262139214Sgibbs } 2622214321Smav 262339214Sgibbs if (error == 0) { 262439214Sgibbs 262539214Sgibbs ccb.ccb_h.func_code = XPT_DEBUG; 262639214Sgibbs ccb.ccb_h.path_id = bus; 262739214Sgibbs ccb.ccb_h.target_id = target; 262839214Sgibbs ccb.ccb_h.target_lun = lun; 262939214Sgibbs 263039214Sgibbs if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 263139214Sgibbs warn("CAMIOCOMMAND ioctl failed"); 263239214Sgibbs error = 1; 263339214Sgibbs } 263439214Sgibbs 263539214Sgibbs if (error == 0) { 263639214Sgibbs if ((ccb.ccb_h.status & CAM_STATUS_MASK) == 263739214Sgibbs CAM_FUNC_NOTAVAIL) { 263839214Sgibbs warnx("CAM debugging not available"); 263939214Sgibbs warnx("you need to put options CAMDEBUG in" 264039214Sgibbs " your kernel config file!"); 264139214Sgibbs error = 1; 264239214Sgibbs } else if ((ccb.ccb_h.status & CAM_STATUS_MASK) != 264339214Sgibbs CAM_REQ_CMP) { 264439214Sgibbs warnx("XPT_DEBUG CCB failed with status %#x", 264539214Sgibbs ccb.ccb_h.status); 264639214Sgibbs error = 1; 264739214Sgibbs } else { 264839214Sgibbs if (ccb.cdbg.flags == CAM_DEBUG_NONE) { 264939214Sgibbs fprintf(stderr, 265039214Sgibbs "Debugging turned off\n"); 265139214Sgibbs } else { 265239214Sgibbs fprintf(stderr, 265339214Sgibbs "Debugging enabled for " 265439214Sgibbs "%d:%d:%d\n", 265539214Sgibbs bus, target, lun); 265639214Sgibbs } 265739214Sgibbs } 265839214Sgibbs } 265939903Sken close(fd); 266039214Sgibbs } 266139214Sgibbs 266239214Sgibbs return(error); 266339214Sgibbs} 266439214Sgibbs 266546581Skenstatic int 266646581Skentagcontrol(struct cam_device *device, int argc, char **argv, 266746581Sken char *combinedopt) 266846581Sken{ 266946581Sken int c; 267046581Sken union ccb *ccb; 267146581Sken int numtags = -1; 267246581Sken int retval = 0; 267346581Sken int quiet = 0; 267446581Sken char pathstr[1024]; 267546581Sken 267646581Sken ccb = cam_getccb(device); 267746581Sken 267846581Sken if (ccb == NULL) { 267946581Sken warnx("tagcontrol: error allocating ccb"); 268046581Sken return(1); 268146581Sken } 268246581Sken 268346581Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 268446581Sken switch(c) { 268546581Sken case 'N': 268646581Sken numtags = strtol(optarg, NULL, 0); 268746581Sken if (numtags < 0) { 268846581Sken warnx("tag count %d is < 0", numtags); 268946581Sken retval = 1; 269046581Sken goto tagcontrol_bailout; 269146581Sken } 269246581Sken break; 269346581Sken case 'q': 269446581Sken quiet++; 269546581Sken break; 269646581Sken default: 269746581Sken break; 269846581Sken } 269946581Sken } 270046581Sken 270146581Sken cam_path_string(device, pathstr, sizeof(pathstr)); 270246581Sken 270346581Sken if (numtags >= 0) { 270446581Sken bzero(&(&ccb->ccb_h)[1], 270546581Sken sizeof(struct ccb_relsim) - sizeof(struct ccb_hdr)); 270646581Sken ccb->ccb_h.func_code = XPT_REL_SIMQ; 270746581Sken ccb->crs.release_flags = RELSIM_ADJUST_OPENINGS; 270846581Sken ccb->crs.openings = numtags; 270946581Sken 271046581Sken 271146581Sken if (cam_send_ccb(device, ccb) < 0) { 271246581Sken perror("error sending XPT_REL_SIMQ CCB"); 271346581Sken retval = 1; 271446581Sken goto tagcontrol_bailout; 271546581Sken } 271646581Sken 271746581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 271874840Sken warnx("XPT_REL_SIMQ CCB failed"); 271974840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 272074840Sken CAM_EPF_ALL, stderr); 272146581Sken retval = 1; 272246581Sken goto tagcontrol_bailout; 272346581Sken } 272446581Sken 272546581Sken 272646581Sken if (quiet == 0) 272746581Sken fprintf(stdout, "%stagged openings now %d\n", 272846581Sken pathstr, ccb->crs.openings); 272946581Sken } 273046581Sken 273146581Sken bzero(&(&ccb->ccb_h)[1], 273293501Sken sizeof(struct ccb_getdevstats) - sizeof(struct ccb_hdr)); 273346581Sken 273456121Smjacob ccb->ccb_h.func_code = XPT_GDEV_STATS; 273546581Sken 273646581Sken if (cam_send_ccb(device, ccb) < 0) { 273756121Smjacob perror("error sending XPT_GDEV_STATS CCB"); 273846581Sken retval = 1; 273946581Sken goto tagcontrol_bailout; 274046581Sken } 274146581Sken 274246581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 274374840Sken warnx("XPT_GDEV_STATS CCB failed"); 274474840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 274574840Sken CAM_EPF_ALL, stderr); 274646581Sken retval = 1; 274746581Sken goto tagcontrol_bailout; 274846581Sken } 274946581Sken 275046581Sken if (arglist & CAM_ARG_VERBOSE) { 275146581Sken fprintf(stdout, "%s", pathstr); 275256121Smjacob fprintf(stdout, "dev_openings %d\n", ccb->cgds.dev_openings); 275346581Sken fprintf(stdout, "%s", pathstr); 275456121Smjacob fprintf(stdout, "dev_active %d\n", ccb->cgds.dev_active); 275546581Sken fprintf(stdout, "%s", pathstr); 275656121Smjacob fprintf(stdout, "devq_openings %d\n", ccb->cgds.devq_openings); 275746581Sken fprintf(stdout, "%s", pathstr); 275856121Smjacob fprintf(stdout, "devq_queued %d\n", ccb->cgds.devq_queued); 275946581Sken fprintf(stdout, "%s", pathstr); 276056121Smjacob fprintf(stdout, "held %d\n", ccb->cgds.held); 276146581Sken fprintf(stdout, "%s", pathstr); 276256121Smjacob fprintf(stdout, "mintags %d\n", ccb->cgds.mintags); 276346581Sken fprintf(stdout, "%s", pathstr); 276456121Smjacob fprintf(stdout, "maxtags %d\n", ccb->cgds.maxtags); 276546581Sken } else { 276646581Sken if (quiet == 0) { 276746581Sken fprintf(stdout, "%s", pathstr); 276846581Sken fprintf(stdout, "device openings: "); 276946581Sken } 277056121Smjacob fprintf(stdout, "%d\n", ccb->cgds.dev_openings + 277156121Smjacob ccb->cgds.dev_active); 277246581Sken } 277346581Sken 277446581Skentagcontrol_bailout: 277546581Sken 277646581Sken cam_freeccb(ccb); 277746581Sken return(retval); 277846581Sken} 277946581Sken 278046581Skenstatic void 278146581Skencts_print(struct cam_device *device, struct ccb_trans_settings *cts) 278246581Sken{ 278346581Sken char pathstr[1024]; 278446581Sken 278546581Sken cam_path_string(device, pathstr, sizeof(pathstr)); 278646581Sken 2787163896Smjacob if (cts->transport == XPORT_SPI) { 2788163896Smjacob struct ccb_trans_settings_spi *spi = 2789163896Smjacob &cts->xport_specific.spi; 279046581Sken 2791163896Smjacob if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) { 279246581Sken 2793163896Smjacob fprintf(stdout, "%ssync parameter: %d\n", pathstr, 2794163896Smjacob spi->sync_period); 279546581Sken 2796163896Smjacob if (spi->sync_offset != 0) { 2797163896Smjacob u_int freq; 2798163896Smjacob 2799163896Smjacob freq = scsi_calc_syncsrate(spi->sync_period); 2800163896Smjacob fprintf(stdout, "%sfrequency: %d.%03dMHz\n", 2801163896Smjacob pathstr, freq / 1000, freq % 1000); 2802163896Smjacob } 280346581Sken } 280446581Sken 2805163896Smjacob if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) { 2806163896Smjacob fprintf(stdout, "%soffset: %d\n", pathstr, 2807163896Smjacob spi->sync_offset); 2808163896Smjacob } 280946581Sken 2810163896Smjacob if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) { 2811163896Smjacob fprintf(stdout, "%sbus width: %d bits\n", pathstr, 2812163896Smjacob (0x01 << spi->bus_width) * 8); 2813163896Smjacob } 281446581Sken 2815163896Smjacob if (spi->valid & CTS_SPI_VALID_DISC) { 2816163896Smjacob fprintf(stdout, "%sdisconnection is %s\n", pathstr, 2817163896Smjacob (spi->flags & CTS_SPI_FLAGS_DISC_ENB) ? 2818163896Smjacob "enabled" : "disabled"); 2819163896Smjacob } 2820163896Smjacob } 2821199747Smav if (cts->transport == XPORT_ATA) { 2822199747Smav struct ccb_trans_settings_ata *ata = 2823199747Smav &cts->xport_specific.ata; 282446581Sken 2825199747Smav if ((ata->valid & CTS_ATA_VALID_MODE) != 0) { 2826199747Smav fprintf(stdout, "%sATA mode: %s\n", pathstr, 2827199747Smav ata_mode2string(ata->mode)); 2828199747Smav } 2829203376Smav if ((ata->valid & CTS_ATA_VALID_ATAPI) != 0) { 2830203376Smav fprintf(stdout, "%sATAPI packet length: %d\n", pathstr, 2831203376Smav ata->atapi); 2832203376Smav } 2833199747Smav if ((ata->valid & CTS_ATA_VALID_BYTECOUNT) != 0) { 2834199747Smav fprintf(stdout, "%sPIO transaction length: %d\n", 2835199747Smav pathstr, ata->bytecount); 2836199747Smav } 2837199747Smav } 2838199747Smav if (cts->transport == XPORT_SATA) { 2839199747Smav struct ccb_trans_settings_sata *sata = 2840199747Smav &cts->xport_specific.sata; 2841199747Smav 2842199747Smav if ((sata->valid & CTS_SATA_VALID_REVISION) != 0) { 2843199747Smav fprintf(stdout, "%sSATA revision: %d.x\n", pathstr, 2844199747Smav sata->revision); 2845199747Smav } 2846199747Smav if ((sata->valid & CTS_SATA_VALID_MODE) != 0) { 2847199747Smav fprintf(stdout, "%sATA mode: %s\n", pathstr, 2848199747Smav ata_mode2string(sata->mode)); 2849199747Smav } 2850203376Smav if ((sata->valid & CTS_SATA_VALID_ATAPI) != 0) { 2851203376Smav fprintf(stdout, "%sATAPI packet length: %d\n", pathstr, 2852203376Smav sata->atapi); 2853203376Smav } 2854199747Smav if ((sata->valid & CTS_SATA_VALID_BYTECOUNT) != 0) { 2855199747Smav fprintf(stdout, "%sPIO transaction length: %d\n", 2856199747Smav pathstr, sata->bytecount); 2857199747Smav } 2858199747Smav if ((sata->valid & CTS_SATA_VALID_PM) != 0) { 2859199747Smav fprintf(stdout, "%sPMP presence: %d\n", pathstr, 2860199747Smav sata->pm_present); 2861199747Smav } 2862199747Smav if ((sata->valid & CTS_SATA_VALID_TAGS) != 0) { 2863199747Smav fprintf(stdout, "%sNumber of tags: %d\n", pathstr, 2864199747Smav sata->tags); 2865199747Smav } 2866207499Smav if ((sata->valid & CTS_SATA_VALID_CAPS) != 0) { 2867207499Smav fprintf(stdout, "%sSATA capabilities: %08x\n", pathstr, 2868207499Smav sata->caps); 2869207499Smav } 2870199747Smav } 2871163896Smjacob if (cts->protocol == PROTO_SCSI) { 2872163896Smjacob struct ccb_trans_settings_scsi *scsi= 2873163896Smjacob &cts->proto_specific.scsi; 287446581Sken 2875163896Smjacob if (scsi->valid & CTS_SCSI_VALID_TQ) { 2876163896Smjacob fprintf(stdout, "%stagged queueing is %s\n", pathstr, 2877163896Smjacob (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) ? 2878163896Smjacob "enabled" : "disabled"); 2879163896Smjacob } 2880163896Smjacob } 2881163896Smjacob 288246581Sken} 288346581Sken 288446581Sken/* 2885214321Smav * Get a path inquiry CCB for the specified device. 288646581Sken */ 288746581Skenstatic int 288846581Skenget_cpi(struct cam_device *device, struct ccb_pathinq *cpi) 288946581Sken{ 289046581Sken union ccb *ccb; 289146581Sken int retval = 0; 289246581Sken 289346581Sken ccb = cam_getccb(device); 289446581Sken if (ccb == NULL) { 289546581Sken warnx("get_cpi: couldn't allocate CCB"); 289646581Sken return(1); 289746581Sken } 289846581Sken bzero(&(&ccb->ccb_h)[1], 289946581Sken sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr)); 290046581Sken ccb->ccb_h.func_code = XPT_PATH_INQ; 290146581Sken if (cam_send_ccb(device, ccb) < 0) { 290246581Sken warn("get_cpi: error sending Path Inquiry CCB"); 290346581Sken if (arglist & CAM_ARG_VERBOSE) 290474840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 290574840Sken CAM_EPF_ALL, stderr); 290646581Sken retval = 1; 290746581Sken goto get_cpi_bailout; 290846581Sken } 290946581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 291046581Sken if (arglist & CAM_ARG_VERBOSE) 291174840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 291274840Sken CAM_EPF_ALL, stderr); 291346581Sken retval = 1; 291446581Sken goto get_cpi_bailout; 291546581Sken } 291646581Sken bcopy(&ccb->cpi, cpi, sizeof(struct ccb_pathinq)); 291746581Sken 291846581Skenget_cpi_bailout: 2919196658Smav cam_freeccb(ccb); 2920196658Smav return(retval); 2921196658Smav} 292246581Sken 2923196658Smav/* 2924214321Smav * Get a get device CCB for the specified device. 2925196658Smav */ 2926196658Smavstatic int 2927196658Smavget_cgd(struct cam_device *device, struct ccb_getdev *cgd) 2928196658Smav{ 2929196658Smav union ccb *ccb; 2930196658Smav int retval = 0; 2931196658Smav 2932196658Smav ccb = cam_getccb(device); 2933196658Smav if (ccb == NULL) { 2934196658Smav warnx("get_cgd: couldn't allocate CCB"); 2935196658Smav return(1); 2936196658Smav } 2937196658Smav bzero(&(&ccb->ccb_h)[1], 2938196658Smav sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr)); 2939196658Smav ccb->ccb_h.func_code = XPT_GDEV_TYPE; 2940196658Smav if (cam_send_ccb(device, ccb) < 0) { 2941196658Smav warn("get_cgd: error sending Path Inquiry CCB"); 2942196658Smav if (arglist & CAM_ARG_VERBOSE) 2943196658Smav cam_error_print(device, ccb, CAM_ESF_ALL, 2944196658Smav CAM_EPF_ALL, stderr); 2945196658Smav retval = 1; 2946196658Smav goto get_cgd_bailout; 2947196658Smav } 2948196658Smav if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2949196658Smav if (arglist & CAM_ARG_VERBOSE) 2950196658Smav cam_error_print(device, ccb, CAM_ESF_ALL, 2951196658Smav CAM_EPF_ALL, stderr); 2952196658Smav retval = 1; 2953196658Smav goto get_cgd_bailout; 2954196658Smav } 2955196658Smav bcopy(&ccb->cgd, cgd, sizeof(struct ccb_getdev)); 2956196658Smav 2957196658Smavget_cgd_bailout: 295846581Sken cam_freeccb(ccb); 295946581Sken return(retval); 296046581Sken} 296146581Sken 296246581Skenstatic void 296346581Skencpi_print(struct ccb_pathinq *cpi) 296446581Sken{ 296546581Sken char adapter_str[1024]; 296646581Sken int i; 296746581Sken 296846581Sken snprintf(adapter_str, sizeof(adapter_str), 296946581Sken "%s%d:", cpi->dev_name, cpi->unit_number); 297046581Sken 297146581Sken fprintf(stdout, "%s SIM/HBA version: %d\n", adapter_str, 297246581Sken cpi->version_num); 297346581Sken 297446581Sken for (i = 1; i < 0xff; i = i << 1) { 2975118478Sjohan const char *str; 297646581Sken 297746581Sken if ((i & cpi->hba_inquiry) == 0) 297846581Sken continue; 297946581Sken 298046581Sken fprintf(stdout, "%s supports ", adapter_str); 298146581Sken 298246581Sken switch(i) { 298346581Sken case PI_MDP_ABLE: 298446581Sken str = "MDP message"; 298546581Sken break; 298646581Sken case PI_WIDE_32: 298746581Sken str = "32 bit wide SCSI"; 298846581Sken break; 298946581Sken case PI_WIDE_16: 299046581Sken str = "16 bit wide SCSI"; 299146581Sken break; 299246581Sken case PI_SDTR_ABLE: 299346581Sken str = "SDTR message"; 299446581Sken break; 299546581Sken case PI_LINKED_CDB: 299646581Sken str = "linked CDBs"; 299746581Sken break; 299846581Sken case PI_TAG_ABLE: 299946581Sken str = "tag queue messages"; 300046581Sken break; 300146581Sken case PI_SOFT_RST: 300246581Sken str = "soft reset alternative"; 300346581Sken break; 3004196658Smav case PI_SATAPM: 3005196658Smav str = "SATA Port Multiplier"; 3006196658Smav break; 300751691Sbillf default: 300851691Sbillf str = "unknown PI bit set"; 300951691Sbillf break; 301046581Sken } 301146581Sken fprintf(stdout, "%s\n", str); 301246581Sken } 301346581Sken 301446581Sken for (i = 1; i < 0xff; i = i << 1) { 3015118478Sjohan const char *str; 301646581Sken 301746581Sken if ((i & cpi->hba_misc) == 0) 301846581Sken continue; 301946581Sken 302046581Sken fprintf(stdout, "%s ", adapter_str); 302146581Sken 302246581Sken switch(i) { 302346581Sken case PIM_SCANHILO: 302446581Sken str = "bus scans from high ID to low ID"; 302546581Sken break; 302646581Sken case PIM_NOREMOVE: 302746581Sken str = "removable devices not included in scan"; 302846581Sken break; 302946581Sken case PIM_NOINITIATOR: 303046581Sken str = "initiator role not supported"; 303146581Sken break; 303246581Sken case PIM_NOBUSRESET: 303346581Sken str = "user has disabled initial BUS RESET or" 303446581Sken " controller is in target/mixed mode"; 303546581Sken break; 3036196658Smav case PIM_NO_6_BYTE: 3037196658Smav str = "do not send 6-byte commands"; 3038196658Smav break; 3039196658Smav case PIM_SEQSCAN: 3040196658Smav str = "scan bus sequentially"; 3041196658Smav break; 304251691Sbillf default: 304351691Sbillf str = "unknown PIM bit set"; 304451691Sbillf break; 304546581Sken } 304646581Sken fprintf(stdout, "%s\n", str); 304746581Sken } 304846581Sken 304946581Sken for (i = 1; i < 0xff; i = i << 1) { 3050118478Sjohan const char *str; 305146581Sken 305246581Sken if ((i & cpi->target_sprt) == 0) 305346581Sken continue; 305446581Sken 305546581Sken fprintf(stdout, "%s supports ", adapter_str); 305646581Sken switch(i) { 305746581Sken case PIT_PROCESSOR: 305846581Sken str = "target mode processor mode"; 305946581Sken break; 306046581Sken case PIT_PHASE: 306146581Sken str = "target mode phase cog. mode"; 306246581Sken break; 306346581Sken case PIT_DISCONNECT: 306446581Sken str = "disconnects in target mode"; 306546581Sken break; 306646581Sken case PIT_TERM_IO: 306746581Sken str = "terminate I/O message in target mode"; 306846581Sken break; 306946581Sken case PIT_GRP_6: 307046581Sken str = "group 6 commands in target mode"; 307146581Sken break; 307246581Sken case PIT_GRP_7: 307346581Sken str = "group 7 commands in target mode"; 307446581Sken break; 307551691Sbillf default: 307651691Sbillf str = "unknown PIT bit set"; 307751691Sbillf break; 307846581Sken } 307946581Sken 308046581Sken fprintf(stdout, "%s\n", str); 308146581Sken } 308246581Sken fprintf(stdout, "%s HBA engine count: %d\n", adapter_str, 308346581Sken cpi->hba_eng_cnt); 308456985Sken fprintf(stdout, "%s maximum target: %d\n", adapter_str, 308546581Sken cpi->max_target); 308656985Sken fprintf(stdout, "%s maximum LUN: %d\n", adapter_str, 308746581Sken cpi->max_lun); 308846581Sken fprintf(stdout, "%s highest path ID in subsystem: %d\n", 308946581Sken adapter_str, cpi->hpath_id); 309066003Sken fprintf(stdout, "%s initiator ID: %d\n", adapter_str, 309166003Sken cpi->initiator_id); 309246581Sken fprintf(stdout, "%s SIM vendor: %s\n", adapter_str, cpi->sim_vid); 309346581Sken fprintf(stdout, "%s HBA vendor: %s\n", adapter_str, cpi->hba_vid); 3094210471Smav fprintf(stdout, "%s HBA vendor ID: 0x%04x\n", 3095210471Smav adapter_str, cpi->hba_vendor); 3096210471Smav fprintf(stdout, "%s HBA device ID: 0x%04x\n", 3097210471Smav adapter_str, cpi->hba_device); 3098210471Smav fprintf(stdout, "%s HBA subvendor ID: 0x%04x\n", 3099210471Smav adapter_str, cpi->hba_subvendor); 3100210471Smav fprintf(stdout, "%s HBA subdevice ID: 0x%04x\n", 3101210471Smav adapter_str, cpi->hba_subdevice); 310246581Sken fprintf(stdout, "%s bus ID: %d\n", adapter_str, cpi->bus_id); 310346581Sken fprintf(stdout, "%s base transfer speed: ", adapter_str); 310446581Sken if (cpi->base_transfer_speed > 1000) 310546581Sken fprintf(stdout, "%d.%03dMB/sec\n", 310646581Sken cpi->base_transfer_speed / 1000, 310746581Sken cpi->base_transfer_speed % 1000); 310846581Sken else 310946581Sken fprintf(stdout, "%dKB/sec\n", 311046581Sken (cpi->base_transfer_speed % 1000) * 1000); 3111210471Smav fprintf(stdout, "%s maximum transfer size: %u bytes\n", 3112210471Smav adapter_str, cpi->maxio); 311346581Sken} 311446581Sken 311546581Skenstatic int 311646581Skenget_print_cts(struct cam_device *device, int user_settings, int quiet, 311746581Sken struct ccb_trans_settings *cts) 311846581Sken{ 311946581Sken int retval; 312046581Sken union ccb *ccb; 312146581Sken 312246581Sken retval = 0; 312346581Sken ccb = cam_getccb(device); 312446581Sken 312546581Sken if (ccb == NULL) { 312646581Sken warnx("get_print_cts: error allocating ccb"); 312746581Sken return(1); 312846581Sken } 312946581Sken 313046581Sken bzero(&(&ccb->ccb_h)[1], 313146581Sken sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr)); 313246581Sken 313346581Sken ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 313446581Sken 313546581Sken if (user_settings == 0) 3136163896Smjacob ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS; 313746581Sken else 3138163896Smjacob ccb->cts.type = CTS_TYPE_USER_SETTINGS; 313946581Sken 314046581Sken if (cam_send_ccb(device, ccb) < 0) { 314146581Sken perror("error sending XPT_GET_TRAN_SETTINGS CCB"); 314274840Sken if (arglist & CAM_ARG_VERBOSE) 314374840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 314474840Sken CAM_EPF_ALL, stderr); 314546581Sken retval = 1; 314646581Sken goto get_print_cts_bailout; 314746581Sken } 314846581Sken 314946581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 315074840Sken warnx("XPT_GET_TRANS_SETTINGS CCB failed"); 315174840Sken if (arglist & CAM_ARG_VERBOSE) 315274840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 315374840Sken CAM_EPF_ALL, stderr); 315446581Sken retval = 1; 315546581Sken goto get_print_cts_bailout; 315646581Sken } 315746581Sken 315846581Sken if (quiet == 0) 315946581Sken cts_print(device, &ccb->cts); 316046581Sken 316146581Sken if (cts != NULL) 316246581Sken bcopy(&ccb->cts, cts, sizeof(struct ccb_trans_settings)); 316346581Sken 316446581Skenget_print_cts_bailout: 316546581Sken 316646581Sken cam_freeccb(ccb); 316746581Sken 316846581Sken return(retval); 316946581Sken} 317046581Sken 317146581Skenstatic int 317246581Skenratecontrol(struct cam_device *device, int retry_count, int timeout, 317346581Sken int argc, char **argv, char *combinedopt) 317446581Sken{ 317546581Sken int c; 317646581Sken union ccb *ccb; 317746581Sken int user_settings = 0; 317846581Sken int retval = 0; 317946581Sken int disc_enable = -1, tag_enable = -1; 3180199821Smav int mode = -1; 318146581Sken int offset = -1; 318246581Sken double syncrate = -1; 318346581Sken int bus_width = -1; 318446581Sken int quiet = 0; 318546581Sken int change_settings = 0, send_tur = 0; 318646581Sken struct ccb_pathinq cpi; 318746581Sken 318846581Sken ccb = cam_getccb(device); 318946581Sken if (ccb == NULL) { 319046581Sken warnx("ratecontrol: error allocating ccb"); 319146581Sken return(1); 319246581Sken } 319346581Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 319446581Sken switch(c){ 319546581Sken case 'a': 319646581Sken send_tur = 1; 319746581Sken break; 319846581Sken case 'c': 319946581Sken user_settings = 0; 320046581Sken break; 320146581Sken case 'D': 320246581Sken if (strncasecmp(optarg, "enable", 6) == 0) 320346581Sken disc_enable = 1; 320446581Sken else if (strncasecmp(optarg, "disable", 7) == 0) 320546581Sken disc_enable = 0; 320646581Sken else { 320746581Sken warnx("-D argument \"%s\" is unknown", optarg); 320846581Sken retval = 1; 320946581Sken goto ratecontrol_bailout; 321046581Sken } 321146581Sken change_settings = 1; 321246581Sken break; 3213199821Smav case 'M': 3214199821Smav mode = ata_string2mode(optarg); 3215199821Smav if (mode < 0) { 3216199821Smav warnx("unknown mode '%s'", optarg); 3217199821Smav retval = 1; 3218199821Smav goto ratecontrol_bailout; 3219199821Smav } 3220199821Smav change_settings = 1; 3221199821Smav break; 322246581Sken case 'O': 322346581Sken offset = strtol(optarg, NULL, 0); 322446581Sken if (offset < 0) { 322546581Sken warnx("offset value %d is < 0", offset); 322646581Sken retval = 1; 322746581Sken goto ratecontrol_bailout; 322846581Sken } 322946581Sken change_settings = 1; 323046581Sken break; 323146581Sken case 'q': 323246581Sken quiet++; 323346581Sken break; 323446581Sken case 'R': 323546581Sken syncrate = atof(optarg); 323646581Sken if (syncrate < 0) { 323746581Sken warnx("sync rate %f is < 0", syncrate); 323846581Sken retval = 1; 323946581Sken goto ratecontrol_bailout; 324046581Sken } 324146581Sken change_settings = 1; 324246581Sken break; 324346581Sken case 'T': 324446581Sken if (strncasecmp(optarg, "enable", 6) == 0) 324546581Sken tag_enable = 1; 324646581Sken else if (strncasecmp(optarg, "disable", 7) == 0) 324746581Sken tag_enable = 0; 324846581Sken else { 324946581Sken warnx("-T argument \"%s\" is unknown", optarg); 325046581Sken retval = 1; 325146581Sken goto ratecontrol_bailout; 325246581Sken } 325346581Sken change_settings = 1; 325446581Sken break; 325546581Sken case 'U': 325646581Sken user_settings = 1; 325746581Sken break; 325846581Sken case 'W': 325946581Sken bus_width = strtol(optarg, NULL, 0); 326046581Sken if (bus_width < 0) { 326146581Sken warnx("bus width %d is < 0", bus_width); 326246581Sken retval = 1; 326346581Sken goto ratecontrol_bailout; 326446581Sken } 326546581Sken change_settings = 1; 326646581Sken break; 326746581Sken default: 326846581Sken break; 326946581Sken } 327046581Sken } 327146581Sken bzero(&(&ccb->ccb_h)[1], 327246581Sken sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr)); 327346581Sken /* 327446581Sken * Grab path inquiry information, so we can determine whether 327546581Sken * or not the initiator is capable of the things that the user 327646581Sken * requests. 327746581Sken */ 327846581Sken ccb->ccb_h.func_code = XPT_PATH_INQ; 327946581Sken if (cam_send_ccb(device, ccb) < 0) { 328046581Sken perror("error sending XPT_PATH_INQ CCB"); 328174840Sken if (arglist & CAM_ARG_VERBOSE) { 328274840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 328374840Sken CAM_EPF_ALL, stderr); 328474840Sken } 328546581Sken retval = 1; 328646581Sken goto ratecontrol_bailout; 328746581Sken } 328846581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 328974840Sken warnx("XPT_PATH_INQ CCB failed"); 329074840Sken if (arglist & CAM_ARG_VERBOSE) { 329174840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 329274840Sken CAM_EPF_ALL, stderr); 329374840Sken } 329446581Sken retval = 1; 329546581Sken goto ratecontrol_bailout; 329646581Sken } 329746581Sken bcopy(&ccb->cpi, &cpi, sizeof(struct ccb_pathinq)); 329846581Sken bzero(&(&ccb->ccb_h)[1], 329946581Sken sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr)); 3300199821Smav if (quiet == 0) { 3301199821Smav fprintf(stdout, "%s parameters:\n", 3302199821Smav user_settings ? "User" : "Current"); 3303199821Smav } 330446581Sken retval = get_print_cts(device, user_settings, quiet, &ccb->cts); 330546581Sken if (retval != 0) 330646581Sken goto ratecontrol_bailout; 330746581Sken 330846581Sken if (arglist & CAM_ARG_VERBOSE) 330946581Sken cpi_print(&cpi); 331046581Sken 331146581Sken if (change_settings) { 3312163896Smjacob int didsettings = 0; 3313163896Smjacob struct ccb_trans_settings_spi *spi = NULL; 3314199821Smav struct ccb_trans_settings_ata *ata = NULL; 3315199821Smav struct ccb_trans_settings_sata *sata = NULL; 3316163896Smjacob struct ccb_trans_settings_scsi *scsi = NULL; 3317163896Smjacob 3318199821Smav if (ccb->cts.transport == XPORT_SPI) 3319163896Smjacob spi = &ccb->cts.xport_specific.spi; 3320199821Smav if (ccb->cts.transport == XPORT_ATA) 3321199821Smav ata = &ccb->cts.xport_specific.ata; 3322199821Smav if (ccb->cts.transport == XPORT_SATA) 3323199821Smav sata = &ccb->cts.xport_specific.sata; 3324199821Smav if (ccb->cts.protocol == PROTO_SCSI) 3325163896Smjacob scsi = &ccb->cts.proto_specific.scsi; 3326199821Smav ccb->cts.xport_specific.valid = 0; 3327199821Smav ccb->cts.proto_specific.valid = 0; 3328163896Smjacob if (spi && disc_enable != -1) { 3329163896Smjacob spi->valid |= CTS_SPI_VALID_DISC; 333046581Sken if (disc_enable == 0) 3331163896Smjacob spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 333246581Sken else 3333163896Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 3334163896Smjacob } 3335163896Smjacob if (scsi && tag_enable != -1) { 333646581Sken if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0) { 333746581Sken warnx("HBA does not support tagged queueing, " 333846581Sken "so you cannot modify tag settings"); 333946581Sken retval = 1; 334046581Sken goto ratecontrol_bailout; 334146581Sken } 3342163896Smjacob scsi->valid |= CTS_SCSI_VALID_TQ; 334346581Sken if (tag_enable == 0) 3344163896Smjacob scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 334546581Sken else 3346163896Smjacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 3347163896Smjacob didsettings++; 3348163896Smjacob } 3349163896Smjacob if (spi && offset != -1) { 335046581Sken if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) { 3351199821Smav warnx("HBA is not capable of changing offset"); 335246581Sken retval = 1; 335346581Sken goto ratecontrol_bailout; 335446581Sken } 3355163896Smjacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 3356163896Smjacob spi->sync_offset = offset; 3357163896Smjacob didsettings++; 3358163896Smjacob } 3359163896Smjacob if (spi && syncrate != -1) { 336046581Sken int prelim_sync_period; 336146581Sken u_int freq; 336246581Sken 336346581Sken if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) { 3364199821Smav warnx("HBA is not capable of changing " 3365199821Smav "transfer rates"); 336646581Sken retval = 1; 336746581Sken goto ratecontrol_bailout; 336846581Sken } 3369163896Smjacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 337046581Sken /* 337146581Sken * The sync rate the user gives us is in MHz. 337246581Sken * We need to translate it into KHz for this 337346581Sken * calculation. 337446581Sken */ 337546581Sken syncrate *= 1000; 337646581Sken /* 337746581Sken * Next, we calculate a "preliminary" sync period 337846581Sken * in tenths of a nanosecond. 337946581Sken */ 338046581Sken if (syncrate == 0) 338146581Sken prelim_sync_period = 0; 338246581Sken else 338346581Sken prelim_sync_period = 10000000 / syncrate; 3384163896Smjacob spi->sync_period = 338546581Sken scsi_calc_syncparam(prelim_sync_period); 3386163896Smjacob freq = scsi_calc_syncsrate(spi->sync_period); 3387163896Smjacob didsettings++; 3388163896Smjacob } 3389199821Smav if (sata && syncrate != -1) { 3390199821Smav if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) { 3391199821Smav warnx("HBA is not capable of changing " 3392199821Smav "transfer rates"); 3393199821Smav retval = 1; 3394199821Smav goto ratecontrol_bailout; 3395199821Smav } 3396199821Smav sata->revision = ata_speed2revision(syncrate * 100); 3397199821Smav if (sata->revision < 0) { 3398199821Smav warnx("Invalid rate %f", syncrate); 3399199821Smav retval = 1; 3400199821Smav goto ratecontrol_bailout; 3401199821Smav } 3402199821Smav sata->valid |= CTS_SATA_VALID_REVISION; 3403199821Smav didsettings++; 3404199821Smav } 3405199821Smav if ((ata || sata) && mode != -1) { 3406199821Smav if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) { 3407199821Smav warnx("HBA is not capable of changing " 3408199821Smav "transfer rates"); 3409199821Smav retval = 1; 3410199821Smav goto ratecontrol_bailout; 3411199821Smav } 3412199821Smav if (ata) { 3413199821Smav ata->mode = mode; 3414199821Smav ata->valid |= CTS_ATA_VALID_MODE; 3415199821Smav } else { 3416199821Smav sata->mode = mode; 3417199821Smav sata->valid |= CTS_SATA_VALID_MODE; 3418199821Smav } 3419199821Smav didsettings++; 3420199821Smav } 342146581Sken /* 342246581Sken * The bus_width argument goes like this: 342346581Sken * 0 == 8 bit 342446581Sken * 1 == 16 bit 342546581Sken * 2 == 32 bit 342646581Sken * Therefore, if you shift the number of bits given on the 342746581Sken * command line right by 4, you should get the correct 342846581Sken * number. 342946581Sken */ 3430163896Smjacob if (spi && bus_width != -1) { 343146581Sken /* 343246581Sken * We might as well validate things here with a 343346581Sken * decipherable error message, rather than what 343446581Sken * will probably be an indecipherable error message 343546581Sken * by the time it gets back to us. 343646581Sken */ 343746581Sken if ((bus_width == 16) 343846581Sken && ((cpi.hba_inquiry & PI_WIDE_16) == 0)) { 343946581Sken warnx("HBA does not support 16 bit bus width"); 344046581Sken retval = 1; 344146581Sken goto ratecontrol_bailout; 344246581Sken } else if ((bus_width == 32) 344346581Sken && ((cpi.hba_inquiry & PI_WIDE_32) == 0)) { 344446581Sken warnx("HBA does not support 32 bit bus width"); 344546581Sken retval = 1; 344646581Sken goto ratecontrol_bailout; 344751723Sken } else if ((bus_width != 8) 344851723Sken && (bus_width != 16) 344951723Sken && (bus_width != 32)) { 345046581Sken warnx("Invalid bus width %d", bus_width); 345146581Sken retval = 1; 345246581Sken goto ratecontrol_bailout; 345346581Sken } 3454163896Smjacob spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 3455163896Smjacob spi->bus_width = bus_width >> 4; 3456163896Smjacob didsettings++; 3457163896Smjacob } 3458163896Smjacob if (didsettings == 0) { 3459163896Smjacob goto ratecontrol_bailout; 3460163896Smjacob } 3461199821Smav if (!user_settings && (ata || sata)) { 3462199821Smav warnx("You can modify only user settings for ATA/SATA"); 3463199821Smav retval = 1; 3464199821Smav goto ratecontrol_bailout; 3465199821Smav } 346646581Sken ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 346746581Sken if (cam_send_ccb(device, ccb) < 0) { 346846581Sken perror("error sending XPT_SET_TRAN_SETTINGS CCB"); 346974840Sken if (arglist & CAM_ARG_VERBOSE) { 347074840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 347174840Sken CAM_EPF_ALL, stderr); 347274840Sken } 347346581Sken retval = 1; 347446581Sken goto ratecontrol_bailout; 347546581Sken } 347646581Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 347774840Sken warnx("XPT_SET_TRANS_SETTINGS CCB failed"); 347874840Sken if (arglist & CAM_ARG_VERBOSE) { 347974840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 348074840Sken CAM_EPF_ALL, stderr); 348174840Sken } 348246581Sken retval = 1; 348346581Sken goto ratecontrol_bailout; 348446581Sken } 348546581Sken } 348646581Sken if (send_tur) { 348746581Sken retval = testunitready(device, retry_count, timeout, 348846581Sken (arglist & CAM_ARG_VERBOSE) ? 0 : 1); 348946581Sken /* 349046581Sken * If the TUR didn't succeed, just bail. 349146581Sken */ 349246581Sken if (retval != 0) { 349346581Sken if (quiet == 0) 349446581Sken fprintf(stderr, "Test Unit Ready failed\n"); 349546581Sken goto ratecontrol_bailout; 349646581Sken } 349746581Sken /* 349846581Sken * If the user wants things quiet, there's no sense in 349946581Sken * getting the transfer settings, if we're not going 350046581Sken * to print them. 350146581Sken */ 350246581Sken if (quiet != 0) 350346581Sken goto ratecontrol_bailout; 3504199821Smav fprintf(stdout, "New parameters:\n"); 350546581Sken retval = get_print_cts(device, user_settings, 0, NULL); 350646581Sken } 350746581Sken 350846581Skenratecontrol_bailout: 350946581Sken cam_freeccb(ccb); 351046581Sken return(retval); 351146581Sken} 351246581Sken 351360767Skenstatic int 351460767Skenscsiformat(struct cam_device *device, int argc, char **argv, 351560767Sken char *combinedopt, int retry_count, int timeout) 351660767Sken{ 351760767Sken union ccb *ccb; 351860767Sken int c; 351960767Sken int ycount = 0, quiet = 0; 352060767Sken int error = 0, response = 0, retval = 0; 352160767Sken int use_timeout = 10800 * 1000; 352260767Sken int immediate = 1; 352360767Sken struct format_defect_list_header fh; 352460767Sken u_int8_t *data_ptr = NULL; 352560767Sken u_int32_t dxfer_len = 0; 352660767Sken u_int8_t byte2 = 0; 352760767Sken int num_warnings = 0; 3528144134Sken int reportonly = 0; 352960767Sken 353060767Sken ccb = cam_getccb(device); 353160767Sken 353260767Sken if (ccb == NULL) { 353360767Sken warnx("scsiformat: error allocating ccb"); 353460767Sken return(1); 353560767Sken } 353660767Sken 353760767Sken bzero(&(&ccb->ccb_h)[1], 353860767Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 353960767Sken 354060767Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 354160767Sken switch(c) { 354260767Sken case 'q': 354360767Sken quiet++; 354460767Sken break; 3545144134Sken case 'r': 3546144134Sken reportonly = 1; 3547144134Sken break; 354860767Sken case 'w': 354960767Sken immediate = 0; 355060767Sken break; 355160767Sken case 'y': 355260767Sken ycount++; 355360767Sken break; 355460767Sken } 355560767Sken } 355660767Sken 3557144134Sken if (reportonly) 3558144134Sken goto doreport; 3559144134Sken 356060767Sken if (quiet == 0) { 356160767Sken fprintf(stdout, "You are about to REMOVE ALL DATA from the " 356260767Sken "following device:\n"); 356360767Sken 356460767Sken error = scsidoinquiry(device, argc, argv, combinedopt, 356560767Sken retry_count, timeout); 356660767Sken 356760767Sken if (error != 0) { 356860767Sken warnx("scsiformat: error sending inquiry"); 356960767Sken goto scsiformat_bailout; 357060767Sken } 357160767Sken } 357260767Sken 357360767Sken if (ycount == 0) { 357460767Sken 357560767Sken do { 357660767Sken char str[1024]; 357760767Sken 357860767Sken fprintf(stdout, "Are you SURE you want to do " 357960767Sken "this? (yes/no) "); 358060767Sken 358160767Sken if (fgets(str, sizeof(str), stdin) != NULL) { 358260767Sken 358360767Sken if (strncasecmp(str, "yes", 3) == 0) 358460767Sken response = 1; 358560767Sken else if (strncasecmp(str, "no", 2) == 0) 358660767Sken response = -1; 358760767Sken else { 358860767Sken fprintf(stdout, "Please answer" 358960767Sken " \"yes\" or \"no\"\n"); 359060767Sken } 359160767Sken } 359260767Sken } while (response == 0); 359360767Sken 359460767Sken if (response == -1) { 359560767Sken error = 1; 359660767Sken goto scsiformat_bailout; 359760767Sken } 359860767Sken } 359960767Sken 360060767Sken if (timeout != 0) 360160767Sken use_timeout = timeout; 360260767Sken 360360767Sken if (quiet == 0) { 360460767Sken fprintf(stdout, "Current format timeout is %d seconds\n", 360560767Sken use_timeout / 1000); 360660767Sken } 360760767Sken 360860767Sken /* 360960767Sken * If the user hasn't disabled questions and didn't specify a 361060767Sken * timeout on the command line, ask them if they want the current 361160767Sken * timeout. 361260767Sken */ 361360767Sken if ((ycount == 0) 361460767Sken && (timeout == 0)) { 361560767Sken char str[1024]; 361660767Sken int new_timeout = 0; 361760767Sken 361860767Sken fprintf(stdout, "Enter new timeout in seconds or press\n" 361960767Sken "return to keep the current timeout [%d] ", 362060767Sken use_timeout / 1000); 362160767Sken 362260767Sken if (fgets(str, sizeof(str), stdin) != NULL) { 362360767Sken if (str[0] != '\0') 362460767Sken new_timeout = atoi(str); 362560767Sken } 362660767Sken 362760767Sken if (new_timeout != 0) { 362860767Sken use_timeout = new_timeout * 1000; 362960767Sken fprintf(stdout, "Using new timeout value %d\n", 363060767Sken use_timeout / 1000); 363160767Sken } 363260767Sken } 363360767Sken 363460767Sken /* 363560767Sken * Keep this outside the if block below to silence any unused 363660767Sken * variable warnings. 363760767Sken */ 363860767Sken bzero(&fh, sizeof(fh)); 363960767Sken 364060767Sken /* 364160767Sken * If we're in immediate mode, we've got to include the format 364260767Sken * header 364360767Sken */ 364460767Sken if (immediate != 0) { 364560767Sken fh.byte2 = FU_DLH_IMMED; 364660767Sken data_ptr = (u_int8_t *)&fh; 364760767Sken dxfer_len = sizeof(fh); 364860767Sken byte2 = FU_FMT_DATA; 364960767Sken } else if (quiet == 0) { 365060767Sken fprintf(stdout, "Formatting..."); 365160767Sken fflush(stdout); 365260767Sken } 365360767Sken 365460767Sken scsi_format_unit(&ccb->csio, 365560767Sken /* retries */ retry_count, 365660767Sken /* cbfcnp */ NULL, 365760767Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 365860767Sken /* byte2 */ byte2, 365960767Sken /* ileave */ 0, 366060767Sken /* data_ptr */ data_ptr, 366160767Sken /* dxfer_len */ dxfer_len, 366260767Sken /* sense_len */ SSD_FULL_SIZE, 366360767Sken /* timeout */ use_timeout); 366460767Sken 366560767Sken /* Disable freezing the device queue */ 366660767Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 366760767Sken 366860767Sken if (arglist & CAM_ARG_ERR_RECOVER) 366960767Sken ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 367060767Sken 367160767Sken if (((retval = cam_send_ccb(device, ccb)) < 0) 367260767Sken || ((immediate == 0) 367360767Sken && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP))) { 367469254Skris const char errstr[] = "error sending format command"; 367560767Sken 367660767Sken if (retval < 0) 367760767Sken warn(errstr); 367860767Sken else 367960767Sken warnx(errstr); 368060767Sken 368160767Sken if (arglist & CAM_ARG_VERBOSE) { 368274840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 368374840Sken CAM_EPF_ALL, stderr); 368460767Sken } 368560767Sken error = 1; 368660767Sken goto scsiformat_bailout; 368760767Sken } 368860767Sken 368960767Sken /* 369060767Sken * If we ran in non-immediate mode, we already checked for errors 369160767Sken * above and printed out any necessary information. If we're in 369260767Sken * immediate mode, we need to loop through and get status 369360767Sken * information periodically. 369460767Sken */ 369560767Sken if (immediate == 0) { 369660767Sken if (quiet == 0) { 369760767Sken fprintf(stdout, "Format Complete\n"); 369860767Sken } 369960767Sken goto scsiformat_bailout; 370060767Sken } 370160767Sken 3702144134Skendoreport: 370360767Sken do { 370460767Sken cam_status status; 370560767Sken 370660767Sken bzero(&(&ccb->ccb_h)[1], 370760767Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 370860767Sken 370960767Sken /* 371060767Sken * There's really no need to do error recovery or 371160767Sken * retries here, since we're just going to sit in a 371260767Sken * loop and wait for the device to finish formatting. 371360767Sken */ 371460767Sken scsi_test_unit_ready(&ccb->csio, 371560767Sken /* retries */ 0, 371660767Sken /* cbfcnp */ NULL, 371760767Sken /* tag_action */ MSG_SIMPLE_Q_TAG, 371860767Sken /* sense_len */ SSD_FULL_SIZE, 371960767Sken /* timeout */ 5000); 372060767Sken 372160767Sken /* Disable freezing the device queue */ 372260767Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 372360767Sken 372460767Sken retval = cam_send_ccb(device, ccb); 372560767Sken 372660767Sken /* 372760767Sken * If we get an error from the ioctl, bail out. SCSI 372860767Sken * errors are expected. 372960767Sken */ 373060767Sken if (retval < 0) { 373160767Sken warn("error sending CAMIOCOMMAND ioctl"); 373260767Sken if (arglist & CAM_ARG_VERBOSE) { 373374840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 373474840Sken CAM_EPF_ALL, stderr); 373560767Sken } 373660767Sken error = 1; 373760767Sken goto scsiformat_bailout; 373860767Sken } 373960767Sken 374060767Sken status = ccb->ccb_h.status & CAM_STATUS_MASK; 374160767Sken 374260767Sken if ((status != CAM_REQ_CMP) 374374840Sken && (status == CAM_SCSI_STATUS_ERROR) 3744144134Sken && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) { 374560767Sken struct scsi_sense_data *sense; 374660767Sken int error_code, sense_key, asc, ascq; 374760767Sken 374860767Sken sense = &ccb->csio.sense_data; 374960767Sken scsi_extract_sense(sense, &error_code, &sense_key, 375060767Sken &asc, &ascq); 375160767Sken 375260767Sken /* 375360767Sken * According to the SCSI-2 and SCSI-3 specs, a 375460767Sken * drive that is in the middle of a format should 375560767Sken * return NOT READY with an ASC of "logical unit 375660767Sken * not ready, format in progress". The sense key 375760767Sken * specific bytes will then be a progress indicator. 375860767Sken */ 375960767Sken if ((sense_key == SSD_KEY_NOT_READY) 376060767Sken && (asc == 0x04) && (ascq == 0x04)) { 376160767Sken if ((sense->extra_len >= 10) 376260767Sken && ((sense->sense_key_spec[0] & 376360767Sken SSD_SCS_VALID) != 0) 376460767Sken && (quiet == 0)) { 376560767Sken int val; 376660767Sken u_int64_t percentage; 376760767Sken 376860767Sken val = scsi_2btoul( 376960767Sken &sense->sense_key_spec[1]); 377060767Sken percentage = 10000 * val; 377160767Sken 377260767Sken fprintf(stdout, 3773111195Sjohan "\rFormatting: %ju.%02u %% " 377460767Sken "(%d/%d) done", 3775214321Smav (uintmax_t)(percentage / 3776111195Sjohan (0x10000 * 100)), 3777214321Smav (unsigned)((percentage / 3778111195Sjohan 0x10000) % 100), 377960767Sken val, 0x10000); 378060767Sken fflush(stdout); 378160767Sken } else if ((quiet == 0) 378260767Sken && (++num_warnings <= 1)) { 378360767Sken warnx("Unexpected SCSI Sense Key " 378460767Sken "Specific value returned " 378560767Sken "during format:"); 378660767Sken scsi_sense_print(device, &ccb->csio, 378760767Sken stderr); 378860767Sken warnx("Unable to print status " 378960767Sken "information, but format will " 379060767Sken "proceed."); 379160767Sken warnx("will exit when format is " 379260767Sken "complete"); 379360767Sken } 379460767Sken sleep(1); 379560767Sken } else { 379660767Sken warnx("Unexpected SCSI error during format"); 379774840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 379874840Sken CAM_EPF_ALL, stderr); 379960767Sken error = 1; 380060767Sken goto scsiformat_bailout; 380160767Sken } 380260767Sken 380360767Sken } else if (status != CAM_REQ_CMP) { 380460767Sken warnx("Unexpected CAM status %#x", status); 380574840Sken if (arglist & CAM_ARG_VERBOSE) 380674840Sken cam_error_print(device, ccb, CAM_ESF_ALL, 380774840Sken CAM_EPF_ALL, stderr); 380860767Sken error = 1; 380960767Sken goto scsiformat_bailout; 381060767Sken } 381160767Sken 381260767Sken } while((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP); 381360767Sken 381460767Sken if (quiet == 0) 381560767Sken fprintf(stdout, "\nFormat Complete\n"); 381660767Sken 381760767Skenscsiformat_bailout: 381860767Sken 381960767Sken cam_freeccb(ccb); 382060767Sken 382160767Sken return(error); 382260767Sken} 3823161506Sken 3824161506Skenstatic int 3825161506Skenscsireportluns(struct cam_device *device, int argc, char **argv, 3826161506Sken char *combinedopt, int retry_count, int timeout) 3827161506Sken{ 3828161506Sken union ccb *ccb; 3829161506Sken int c, countonly, lunsonly; 3830161506Sken struct scsi_report_luns_data *lundata; 3831161506Sken int alloc_len; 3832161506Sken uint8_t report_type; 3833161506Sken uint32_t list_len, i, j; 3834161506Sken int retval; 3835161506Sken 3836161506Sken retval = 0; 3837161506Sken lundata = NULL; 3838161506Sken report_type = RPL_REPORT_DEFAULT; 3839161506Sken ccb = cam_getccb(device); 3840161506Sken 3841161506Sken if (ccb == NULL) { 3842161506Sken warnx("%s: error allocating ccb", __func__); 3843161506Sken return (1); 3844161506Sken } 3845161506Sken 3846161506Sken bzero(&(&ccb->ccb_h)[1], 3847161506Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 3848161506Sken 3849161506Sken countonly = 0; 3850161506Sken lunsonly = 0; 3851161506Sken 3852161506Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 3853161506Sken switch (c) { 3854161506Sken case 'c': 3855161506Sken countonly++; 3856161506Sken break; 3857161506Sken case 'l': 3858161506Sken lunsonly++; 3859161506Sken break; 3860161506Sken case 'r': 3861161506Sken if (strcasecmp(optarg, "default") == 0) 3862161506Sken report_type = RPL_REPORT_DEFAULT; 3863161506Sken else if (strcasecmp(optarg, "wellknown") == 0) 3864161506Sken report_type = RPL_REPORT_WELLKNOWN; 3865161506Sken else if (strcasecmp(optarg, "all") == 0) 3866161506Sken report_type = RPL_REPORT_ALL; 3867161506Sken else { 3868161506Sken warnx("%s: invalid report type \"%s\"", 3869161506Sken __func__, optarg); 3870161506Sken retval = 1; 3871161506Sken goto bailout; 3872161506Sken } 3873161506Sken break; 3874161506Sken default: 3875161506Sken break; 3876161506Sken } 3877161506Sken } 3878161506Sken 3879161506Sken if ((countonly != 0) 3880161506Sken && (lunsonly != 0)) { 3881161506Sken warnx("%s: you can only specify one of -c or -l", __func__); 3882161506Sken retval = 1; 3883161506Sken goto bailout; 3884161506Sken } 3885161506Sken /* 3886161506Sken * According to SPC-4, the allocation length must be at least 16 3887161506Sken * bytes -- enough for the header and one LUN. 3888161506Sken */ 3889161506Sken alloc_len = sizeof(*lundata) + 8; 3890161506Sken 3891161506Skenretry: 3892161506Sken 3893161506Sken lundata = malloc(alloc_len); 3894161506Sken 3895161506Sken if (lundata == NULL) { 3896161506Sken warn("%s: error mallocing %d bytes", __func__, alloc_len); 3897161506Sken retval = 1; 3898161506Sken goto bailout; 3899161506Sken } 3900161506Sken 3901161506Sken scsi_report_luns(&ccb->csio, 3902161506Sken /*retries*/ retry_count, 3903161506Sken /*cbfcnp*/ NULL, 3904161506Sken /*tag_action*/ MSG_SIMPLE_Q_TAG, 3905161506Sken /*select_report*/ report_type, 3906161506Sken /*rpl_buf*/ lundata, 3907161506Sken /*alloc_len*/ alloc_len, 3908161506Sken /*sense_len*/ SSD_FULL_SIZE, 3909161506Sken /*timeout*/ timeout ? timeout : 5000); 3910161506Sken 3911161506Sken /* Disable freezing the device queue */ 3912161506Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 3913161506Sken 3914161506Sken if (arglist & CAM_ARG_ERR_RECOVER) 3915161506Sken ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 3916161506Sken 3917161506Sken if (cam_send_ccb(device, ccb) < 0) { 3918161506Sken warn("error sending REPORT LUNS command"); 3919161506Sken 3920161506Sken if (arglist & CAM_ARG_VERBOSE) 3921161506Sken cam_error_print(device, ccb, CAM_ESF_ALL, 3922161506Sken CAM_EPF_ALL, stderr); 3923161506Sken 3924161506Sken retval = 1; 3925161506Sken goto bailout; 3926161506Sken } 3927161506Sken 3928161506Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 3929161506Sken cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); 3930161506Sken retval = 1; 3931161506Sken goto bailout; 3932161506Sken } 3933161506Sken 3934161506Sken 3935161506Sken list_len = scsi_4btoul(lundata->length); 3936161506Sken 3937161506Sken /* 3938161506Sken * If we need to list the LUNs, and our allocation 3939161506Sken * length was too short, reallocate and retry. 3940161506Sken */ 3941161506Sken if ((countonly == 0) 3942161506Sken && (list_len > (alloc_len - sizeof(*lundata)))) { 3943161506Sken alloc_len = list_len + sizeof(*lundata); 3944161506Sken free(lundata); 3945161506Sken goto retry; 3946161506Sken } 3947161506Sken 3948161506Sken if (lunsonly == 0) 3949161506Sken fprintf(stdout, "%u LUN%s found\n", list_len / 8, 3950161506Sken ((list_len / 8) > 1) ? "s" : ""); 3951161506Sken 3952161506Sken if (countonly != 0) 3953161506Sken goto bailout; 3954161506Sken 3955161506Sken for (i = 0; i < (list_len / 8); i++) { 3956161506Sken int no_more; 3957161506Sken 3958161506Sken no_more = 0; 3959161506Sken for (j = 0; j < sizeof(lundata->luns[i].lundata); j += 2) { 3960161506Sken if (j != 0) 3961161506Sken fprintf(stdout, ","); 3962161506Sken switch (lundata->luns[i].lundata[j] & 3963161506Sken RPL_LUNDATA_ATYP_MASK) { 3964161506Sken case RPL_LUNDATA_ATYP_PERIPH: 3965161506Sken if ((lundata->luns[i].lundata[j] & 3966161506Sken RPL_LUNDATA_PERIPH_BUS_MASK) != 0) 3967214321Smav fprintf(stdout, "%d:", 3968161506Sken lundata->luns[i].lundata[j] & 3969161506Sken RPL_LUNDATA_PERIPH_BUS_MASK); 3970161506Sken else if ((j == 0) 3971161506Sken && ((lundata->luns[i].lundata[j+2] & 3972161506Sken RPL_LUNDATA_PERIPH_BUS_MASK) == 0)) 3973161506Sken no_more = 1; 3974161506Sken 3975161506Sken fprintf(stdout, "%d", 3976161506Sken lundata->luns[i].lundata[j+1]); 3977161506Sken break; 3978161506Sken case RPL_LUNDATA_ATYP_FLAT: { 3979161506Sken uint8_t tmplun[2]; 3980161506Sken tmplun[0] = lundata->luns[i].lundata[j] & 3981161506Sken RPL_LUNDATA_FLAT_LUN_MASK; 3982161506Sken tmplun[1] = lundata->luns[i].lundata[j+1]; 3983161506Sken 3984161506Sken fprintf(stdout, "%d", scsi_2btoul(tmplun)); 3985161506Sken no_more = 1; 3986161506Sken break; 3987161506Sken } 3988161506Sken case RPL_LUNDATA_ATYP_LUN: 3989161506Sken fprintf(stdout, "%d:%d:%d", 3990161506Sken (lundata->luns[i].lundata[j+1] & 3991161506Sken RPL_LUNDATA_LUN_BUS_MASK) >> 5, 3992161506Sken lundata->luns[i].lundata[j] & 3993161506Sken RPL_LUNDATA_LUN_TARG_MASK, 3994161506Sken lundata->luns[i].lundata[j+1] & 3995161506Sken RPL_LUNDATA_LUN_LUN_MASK); 3996161506Sken break; 3997161506Sken case RPL_LUNDATA_ATYP_EXTLUN: { 3998161506Sken int field_len, field_len_code, eam_code; 3999161506Sken 4000161506Sken eam_code = lundata->luns[i].lundata[j] & 4001161506Sken RPL_LUNDATA_EXT_EAM_MASK; 4002161506Sken field_len_code = (lundata->luns[i].lundata[j] & 4003161506Sken RPL_LUNDATA_EXT_LEN_MASK) >> 4; 4004161506Sken field_len = field_len_code * 2; 4005214321Smav 4006161506Sken if ((eam_code == RPL_LUNDATA_EXT_EAM_WK) 4007161506Sken && (field_len_code == 0x00)) { 4008161506Sken fprintf(stdout, "%d", 4009161506Sken lundata->luns[i].lundata[j+1]); 4010161506Sken } else if ((eam_code == 4011161506Sken RPL_LUNDATA_EXT_EAM_NOT_SPEC) 4012161506Sken && (field_len_code == 0x03)) { 4013161506Sken uint8_t tmp_lun[8]; 4014161506Sken 4015161506Sken /* 4016161506Sken * This format takes up all 8 bytes. 4017161506Sken * If we aren't starting at offset 0, 4018161506Sken * that's a bug. 4019161506Sken */ 4020161506Sken if (j != 0) { 4021161506Sken fprintf(stdout, "Invalid " 4022161506Sken "offset %d for " 4023161506Sken "Extended LUN not " 4024161506Sken "specified format", j); 4025161506Sken no_more = 1; 4026161506Sken break; 4027161506Sken } 4028161506Sken bzero(tmp_lun, sizeof(tmp_lun)); 4029161506Sken bcopy(&lundata->luns[i].lundata[j+1], 4030161506Sken &tmp_lun[1], sizeof(tmp_lun) - 1); 4031161506Sken fprintf(stdout, "%#jx", 4032161506Sken (intmax_t)scsi_8btou64(tmp_lun)); 4033161506Sken no_more = 1; 4034161506Sken } else { 4035161506Sken fprintf(stderr, "Unknown Extended LUN" 4036161506Sken "Address method %#x, length " 4037161506Sken "code %#x", eam_code, 4038161506Sken field_len_code); 4039161506Sken no_more = 1; 4040161506Sken } 4041161506Sken break; 4042161506Sken } 4043161506Sken default: 4044161506Sken fprintf(stderr, "Unknown LUN address method " 4045161506Sken "%#x\n", lundata->luns[i].lundata[0] & 4046161506Sken RPL_LUNDATA_ATYP_MASK); 4047161506Sken break; 4048161506Sken } 4049161506Sken /* 4050161506Sken * For the flat addressing method, there are no 4051161506Sken * other levels after it. 4052161506Sken */ 4053161506Sken if (no_more != 0) 4054161506Sken break; 4055161506Sken } 4056161506Sken fprintf(stdout, "\n"); 4057161506Sken } 4058161506Sken 4059161506Skenbailout: 4060161506Sken 4061161506Sken cam_freeccb(ccb); 4062161506Sken 4063161506Sken free(lundata); 4064161506Sken 4065161506Sken return (retval); 4066161506Sken} 4067161506Sken 4068172093Skenstatic int 4069172093Skenscsireadcapacity(struct cam_device *device, int argc, char **argv, 4070172093Sken char *combinedopt, int retry_count, int timeout) 4071172093Sken{ 4072172093Sken union ccb *ccb; 4073172093Sken int blocksizeonly, humanize, numblocks, quiet, sizeonly, baseten; 4074172093Sken struct scsi_read_capacity_data rcap; 4075172093Sken struct scsi_read_capacity_data_long rcaplong; 4076172093Sken uint64_t maxsector; 4077172093Sken uint32_t block_len; 4078172093Sken int retval; 4079172093Sken int c; 4080172093Sken 4081172093Sken blocksizeonly = 0; 4082172093Sken humanize = 0; 4083172093Sken numblocks = 0; 4084172093Sken quiet = 0; 4085172093Sken sizeonly = 0; 4086172093Sken baseten = 0; 4087172093Sken retval = 0; 4088172093Sken 4089172093Sken ccb = cam_getccb(device); 4090172093Sken 4091172093Sken if (ccb == NULL) { 4092172093Sken warnx("%s: error allocating ccb", __func__); 4093172093Sken return (1); 4094172093Sken } 4095172093Sken 4096172093Sken bzero(&(&ccb->ccb_h)[1], 4097172093Sken sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 4098172093Sken 4099172093Sken while ((c = getopt(argc, argv, combinedopt)) != -1) { 4100172093Sken switch (c) { 4101172093Sken case 'b': 4102172093Sken blocksizeonly++; 4103172093Sken break; 4104172093Sken case 'h': 4105172093Sken humanize++; 4106172093Sken baseten = 0; 4107172093Sken break; 4108172093Sken case 'H': 4109172093Sken humanize++; 4110172093Sken baseten++; 4111172093Sken break; 4112172093Sken case 'N': 4113172093Sken numblocks++; 4114172093Sken break; 4115172093Sken case 'q': 4116172093Sken quiet++; 4117172093Sken break; 4118172093Sken case 's': 4119172093Sken sizeonly++; 4120172093Sken break; 4121172093Sken default: 4122172093Sken break; 4123172093Sken } 4124172093Sken } 4125172093Sken 4126172093Sken if ((blocksizeonly != 0) 4127172093Sken && (numblocks != 0)) { 4128172093Sken warnx("%s: you can only specify one of -b or -N", __func__); 4129172093Sken retval = 1; 4130172093Sken goto bailout; 4131172093Sken } 4132172093Sken 4133172093Sken if ((blocksizeonly != 0) 4134172093Sken && (sizeonly != 0)) { 4135172093Sken warnx("%s: you can only specify one of -b or -s", __func__); 4136172093Sken retval = 1; 4137172093Sken goto bailout; 4138172093Sken } 4139172093Sken 4140172093Sken if ((humanize != 0) 4141172093Sken && (quiet != 0)) { 4142172093Sken warnx("%s: you can only specify one of -h/-H or -q", __func__); 4143172093Sken retval = 1; 4144172093Sken goto bailout; 4145172093Sken } 4146172093Sken 4147172093Sken if ((humanize != 0) 4148172093Sken && (blocksizeonly != 0)) { 4149172093Sken warnx("%s: you can only specify one of -h/-H or -b", __func__); 4150172093Sken retval = 1; 4151172093Sken goto bailout; 4152172093Sken } 4153172093Sken 4154172093Sken scsi_read_capacity(&ccb->csio, 4155172093Sken /*retries*/ retry_count, 4156172093Sken /*cbfcnp*/ NULL, 4157172093Sken /*tag_action*/ MSG_SIMPLE_Q_TAG, 4158172093Sken &rcap, 4159172093Sken SSD_FULL_SIZE, 4160172093Sken /*timeout*/ timeout ? timeout : 5000); 4161172093Sken 4162172093Sken /* Disable freezing the device queue */ 4163172093Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 4164172093Sken 4165172093Sken if (arglist & CAM_ARG_ERR_RECOVER) 4166172093Sken ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 4167172093Sken 4168172093Sken if (cam_send_ccb(device, ccb) < 0) { 4169172093Sken warn("error sending READ CAPACITY command"); 4170172093Sken 4171172093Sken if (arglist & CAM_ARG_VERBOSE) 4172172093Sken cam_error_print(device, ccb, CAM_ESF_ALL, 4173172093Sken CAM_EPF_ALL, stderr); 4174172093Sken 4175172093Sken retval = 1; 4176172093Sken goto bailout; 4177172093Sken } 4178172093Sken 4179172093Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 4180172093Sken cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); 4181172093Sken retval = 1; 4182172093Sken goto bailout; 4183172093Sken } 4184172093Sken 4185172093Sken maxsector = scsi_4btoul(rcap.addr); 4186172093Sken block_len = scsi_4btoul(rcap.length); 4187172093Sken 4188172093Sken /* 4189172093Sken * A last block of 2^32-1 means that the true capacity is over 2TB, 4190172093Sken * and we need to issue the long READ CAPACITY to get the real 4191172093Sken * capacity. Otherwise, we're all set. 4192172093Sken */ 4193172093Sken if (maxsector != 0xffffffff) 4194172093Sken goto do_print; 4195172093Sken 4196172093Sken scsi_read_capacity_16(&ccb->csio, 4197172093Sken /*retries*/ retry_count, 4198172093Sken /*cbfcnp*/ NULL, 4199172093Sken /*tag_action*/ MSG_SIMPLE_Q_TAG, 4200172093Sken /*lba*/ 0, 4201172093Sken /*reladdr*/ 0, 4202172093Sken /*pmi*/ 0, 4203172093Sken &rcaplong, 4204172093Sken /*sense_len*/ SSD_FULL_SIZE, 4205172093Sken /*timeout*/ timeout ? timeout : 5000); 4206172093Sken 4207172093Sken /* Disable freezing the device queue */ 4208172093Sken ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 4209172093Sken 4210172093Sken if (arglist & CAM_ARG_ERR_RECOVER) 4211172093Sken ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 4212172093Sken 4213172093Sken if (cam_send_ccb(device, ccb) < 0) { 4214172093Sken warn("error sending READ CAPACITY (16) command"); 4215172093Sken 4216172093Sken if (arglist & CAM_ARG_VERBOSE) 4217172093Sken cam_error_print(device, ccb, CAM_ESF_ALL, 4218172093Sken CAM_EPF_ALL, stderr); 4219172093Sken 4220172093Sken retval = 1; 4221172093Sken goto bailout; 4222172093Sken } 4223172093Sken 4224172093Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 4225172093Sken cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); 4226172093Sken retval = 1; 4227172093Sken goto bailout; 4228172093Sken } 4229172093Sken 4230172093Sken maxsector = scsi_8btou64(rcaplong.addr); 4231172093Sken block_len = scsi_4btoul(rcaplong.length); 4232172093Sken 4233172093Skendo_print: 4234172093Sken if (blocksizeonly == 0) { 4235172093Sken /* 4236172093Sken * Humanize implies !quiet, and also implies numblocks. 4237172093Sken */ 4238172093Sken if (humanize != 0) { 4239172093Sken char tmpstr[6]; 4240172093Sken int64_t tmpbytes; 4241172093Sken int ret; 4242172093Sken 4243172093Sken tmpbytes = (maxsector + 1) * block_len; 4244172093Sken ret = humanize_number(tmpstr, sizeof(tmpstr), 4245172093Sken tmpbytes, "", HN_AUTOSCALE, 4246172093Sken HN_B | HN_DECIMAL | 4247172093Sken ((baseten != 0) ? 4248172093Sken HN_DIVISOR_1000 : 0)); 4249172093Sken if (ret == -1) { 4250172093Sken warnx("%s: humanize_number failed!", __func__); 4251172093Sken retval = 1; 4252172093Sken goto bailout; 4253172093Sken } 4254172093Sken fprintf(stdout, "Device Size: %s%s", tmpstr, 4255172093Sken (sizeonly == 0) ? ", " : "\n"); 4256172093Sken } else if (numblocks != 0) { 4257172093Sken fprintf(stdout, "%s%ju%s", (quiet == 0) ? 4258172093Sken "Blocks: " : "", (uintmax_t)maxsector + 1, 4259172093Sken (sizeonly == 0) ? ", " : "\n"); 4260172093Sken } else { 4261172093Sken fprintf(stdout, "%s%ju%s", (quiet == 0) ? 4262172093Sken "Last Block: " : "", (uintmax_t)maxsector, 4263172093Sken (sizeonly == 0) ? ", " : "\n"); 4264172093Sken } 4265172093Sken } 4266172093Sken if (sizeonly == 0) 4267172093Sken fprintf(stdout, "%s%u%s\n", (quiet == 0) ? 4268172093Sken "Block Length: " : "", block_len, (quiet == 0) ? 4269172093Sken " bytes" : ""); 4270172093Skenbailout: 4271172093Sken cam_freeccb(ccb); 4272172093Sken 4273172093Sken return (retval); 4274172093Sken} 4275172093Sken 4276199079Smavstatic int 4277199079Smavatapm(struct cam_device *device, int argc, char **argv, 4278199079Smav char *combinedopt, int retry_count, int timeout) 4279199079Smav{ 4280199079Smav union ccb *ccb; 4281199079Smav int retval = 0; 4282199079Smav int t = -1; 4283199101Smav int c; 4284199079Smav u_char cmd, sc; 4285199079Smav 4286199079Smav ccb = cam_getccb(device); 4287199079Smav 4288199079Smav if (ccb == NULL) { 4289199079Smav warnx("%s: error allocating ccb", __func__); 4290199079Smav return (1); 4291199079Smav } 4292199079Smav 4293199079Smav while ((c = getopt(argc, argv, combinedopt)) != -1) { 4294199079Smav switch (c) { 4295199079Smav case 't': 4296199079Smav t = atoi(optarg); 4297199079Smav break; 4298199079Smav default: 4299199079Smav break; 4300199079Smav } 4301199079Smav } 4302199079Smav if (strcmp(argv[1], "idle") == 0) { 4303199079Smav if (t == -1) 4304199079Smav cmd = ATA_IDLE_IMMEDIATE; 4305199079Smav else 4306199079Smav cmd = ATA_IDLE_CMD; 4307199079Smav } else if (strcmp(argv[1], "standby") == 0) { 4308199079Smav if (t == -1) 4309199079Smav cmd = ATA_STANDBY_IMMEDIATE; 4310199079Smav else 4311199079Smav cmd = ATA_STANDBY_CMD; 4312199079Smav } else { 4313199079Smav cmd = ATA_SLEEP; 4314199079Smav t = -1; 4315199079Smav } 4316214807Sbrucec 4317199079Smav if (t < 0) 4318199079Smav sc = 0; 4319199079Smav else if (t <= (240 * 5)) 4320214807Sbrucec sc = (t + 4) / 5; 4321214807Sbrucec else if (t <= (252 * 5)) 4322214781Sbrucec /* special encoding for 21 minutes */ 4323214781Sbrucec sc = 252; 4324199079Smav else if (t <= (11 * 30 * 60)) 4325214807Sbrucec sc = (t - 1) / (30 * 60) + 241; 4326199079Smav else 4327199079Smav sc = 253; 4328214781Sbrucec 4329199079Smav cam_fill_ataio(&ccb->ataio, 4330199079Smav retry_count, 4331199079Smav NULL, 4332199079Smav /*flags*/CAM_DIR_NONE, 4333199079Smav MSG_SIMPLE_Q_TAG, 4334199079Smav /*data_ptr*/NULL, 4335199079Smav /*dxfer_len*/0, 4336199079Smav timeout ? timeout : 30 * 1000); 4337199079Smav ata_28bit_cmd(&ccb->ataio, cmd, 0, 0, sc); 4338199079Smav 4339199079Smav /* Disable freezing the device queue */ 4340199079Smav ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 4341199079Smav 4342199079Smav if (arglist & CAM_ARG_ERR_RECOVER) 4343199079Smav ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 4344199079Smav 4345199079Smav if (cam_send_ccb(device, ccb) < 0) { 4346199079Smav warn("error sending command"); 4347199079Smav 4348199079Smav if (arglist & CAM_ARG_VERBOSE) 4349199079Smav cam_error_print(device, ccb, CAM_ESF_ALL, 4350199079Smav CAM_EPF_ALL, stderr); 4351199079Smav 4352199079Smav retval = 1; 4353199079Smav goto bailout; 4354199079Smav } 4355199079Smav 4356199079Smav if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 4357199079Smav cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); 4358199079Smav retval = 1; 4359199079Smav goto bailout; 4360199079Smav } 4361199079Smavbailout: 4362199079Smav cam_freeccb(ccb); 4363199079Smav return (retval); 4364199079Smav} 4365199079Smav 436689471Sjoerg#endif /* MINIMALISTIC */ 436760767Sken 4368214321Smavvoid 436946938Skenusage(int verbose) 437039214Sgibbs{ 437161228Sken fprintf(verbose ? stdout : stderr, 437246938Sken"usage: camcontrol <command> [device id][generic args][command args]\n" 437389521Sjoerg" camcontrol devlist [-v]\n" 437489471Sjoerg#ifndef MINIMALISTIC 437546938Sken" camcontrol periphlist [dev_id][-n dev_name] [-u unit]\n" 437646938Sken" camcontrol tur [dev_id][generic args]\n" 437746938Sken" camcontrol inquiry [dev_id][generic args] [-D] [-S] [-R]\n" 4378202694Smav" camcontrol identify [dev_id][generic args] [-v]\n" 4379161506Sken" camcontrol reportluns [dev_id][generic args] [-c] [-l] [-r report]\n" 4380172093Sken" camcontrol readcap [dev_id][generic args] [-b] [-h] [-H] [-N]\n" 4381172093Sken" [-q] [-s]\n" 438246938Sken" camcontrol start [dev_id][generic args]\n" 438346938Sken" camcontrol stop [dev_id][generic args]\n" 4384103033Smdodd" camcontrol load [dev_id][generic args]\n" 438546938Sken" camcontrol eject [dev_id][generic args]\n" 438689471Sjoerg#endif /* MINIMALISTIC */ 438789515Sken" camcontrol rescan <all | bus[:target:lun]>\n" 438889515Sken" camcontrol reset <all | bus[:target:lun]>\n" 438989471Sjoerg#ifndef MINIMALISTIC 439046938Sken" camcontrol defects [dev_id][generic args] <-f format> [-P][-G]\n" 439164382Skbyanc" camcontrol modepage [dev_id][generic args] <-m page | -l>\n" 439264382Skbyanc" [-P pagectl][-e | -b][-d]\n" 4393196831Smav" camcontrol cmd [dev_id][generic args]\n" 4394196831Smav" <-a cmd [args] | -c cmd [args]>\n" 4395207498Smav" [-d] [-f] [-i len fmt|-o len fmt [args]] [-r fmt]\n" 4396107966Snjl" camcontrol debug [-I][-P][-T][-S][-X][-c]\n" 4397107966Snjl" <all|bus[:target[:lun]]|off>\n" 439846938Sken" camcontrol tags [dev_id][generic args] [-N tags] [-q] [-v]\n" 439946938Sken" camcontrol negotiate [dev_id][generic args] [-a][-c]\n" 4400199821Smav" [-D <enable|disable>][-M mode][-O offset]\n" 4401199821Smav" [-q][-R syncrate][-v][-T <enable|disable>]\n" 440246938Sken" [-U][-W bus_width]\n" 4403144134Sken" camcontrol format [dev_id][generic args][-q][-r][-w][-y]\n" 4404199079Smav" camcontrol idle [dev_id][generic args][-t time]\n" 4405199079Smav" camcontrol standby [dev_id][generic args][-t time]\n" 4406199079Smav" camcontrol sleep [dev_id][generic args]\n" 440789471Sjoerg#endif /* MINIMALISTIC */ 440846938Sken" camcontrol help\n"); 440946938Sken if (!verbose) 441046938Sken return; 441189471Sjoerg#ifndef MINIMALISTIC 441261228Sken fprintf(stdout, 441339214Sgibbs"Specify one of the following options:\n" 441439214Sgibbs"devlist list all CAM devices\n" 441539214Sgibbs"periphlist list all CAM peripheral drivers attached to a device\n" 441639214Sgibbs"tur send a test unit ready to the named device\n" 441739214Sgibbs"inquiry send a SCSI inquiry command to the named device\n" 4418195534Sscottl"identify send a ATA identify command to the named device\n" 4419161506Sken"reportluns send a SCSI report luns command to the device\n" 4420172093Sken"readcap send a SCSI read capacity command to the device\n" 442139214Sgibbs"start send a Start Unit command to the device\n" 442239214Sgibbs"stop send a Stop Unit command to the device\n" 4423103033Smdodd"load send a Start Unit command to the device with the load bit set\n" 442439214Sgibbs"eject send a Stop Unit command to the device with the eject bit set\n" 442589515Sken"rescan rescan all busses, the given bus, or bus:target:lun\n" 442689515Sken"reset reset all busses, the given bus, or bus:target:lun\n" 442739214Sgibbs"defects read the defect list of the specified device\n" 442839214Sgibbs"modepage display or edit (-e) the given mode page\n" 442939214Sgibbs"cmd send the given scsi command, may need -i or -o as well\n" 443039214Sgibbs"debug turn debugging on/off for a bus, target, or lun, or all devices\n" 443146581Sken"tags report or set the number of transaction slots for a device\n" 443246581Sken"negotiate report or set device negotiation parameters\n" 443360767Sken"format send the SCSI FORMAT UNIT command to the named device\n" 4434199079Smav"idle send the ATA IDLE command to the named device\n" 4435199079Smav"standby send the ATA STANDBY command to the named device\n" 4436199079Smav"sleep send the ATA SLEEP command to the named device\n" 443746938Sken"help this message\n" 443846938Sken"Device Identifiers:\n" 443946938Sken"bus:target specify the bus and target, lun defaults to 0\n" 444046938Sken"bus:target:lun specify the bus, target and lun\n" 444146938Sken"deviceUNIT specify the device name, like \"da4\" or \"cd2\"\n" 444239214Sgibbs"Generic arguments:\n" 444339214Sgibbs"-v be verbose, print out sense information\n" 444439214Sgibbs"-t timeout command timeout in seconds, overrides default timeout\n" 444561233Sken"-n dev_name specify device name, e.g. \"da\", \"cd\"\n" 444661233Sken"-u unit specify unit number, e.g. \"0\", \"5\"\n" 444739214Sgibbs"-E have the kernel attempt to perform SCSI error recovery\n" 444839214Sgibbs"-C count specify the SCSI command retry count (needs -E to work)\n" 444939214Sgibbs"modepage arguments:\n" 445064468Skbyanc"-l list all available mode pages\n" 445146581Sken"-m page specify the mode page to view or edit\n" 445239214Sgibbs"-e edit the specified mode page\n" 445364382Skbyanc"-b force view to binary mode\n" 445446581Sken"-d disable block descriptors for mode sense\n" 445539214Sgibbs"-P pgctl page control field 0-3\n" 445639214Sgibbs"defects arguments:\n" 445739214Sgibbs"-f format specify defect list format (block, bfi or phys)\n" 445839214Sgibbs"-G get the grown defect list\n" 445939214Sgibbs"-P get the permanant defect list\n" 446039214Sgibbs"inquiry arguments:\n" 446139214Sgibbs"-D get the standard inquiry data\n" 446239214Sgibbs"-S get the serial number\n" 446339214Sgibbs"-R get the transfer rate, etc.\n" 4464161506Sken"reportluns arguments:\n" 4465161506Sken"-c only report a count of available LUNs\n" 4466161506Sken"-l only print out luns, and not a count\n" 4467161506Sken"-r <reporttype> specify \"default\", \"wellknown\" or \"all\"\n" 4468172093Sken"readcap arguments\n" 4469172093Sken"-b only report the blocksize\n" 4470172093Sken"-h human readable device size, base 2\n" 4471172093Sken"-H human readable device size, base 10\n" 4472172093Sken"-N print the number of blocks instead of last block\n" 4473172093Sken"-q quiet, print numbers only\n" 4474172093Sken"-s only report the last block/device size\n" 447539214Sgibbs"cmd arguments:\n" 447639214Sgibbs"-c cdb [args] specify the SCSI CDB\n" 447739214Sgibbs"-i len fmt specify input data and input data format\n" 447839214Sgibbs"-o len fmt [args] specify output data and output data fmt\n" 447939214Sgibbs"debug arguments:\n" 448039214Sgibbs"-I CAM_DEBUG_INFO -- scsi commands, errors, data\n" 448139214Sgibbs"-T CAM_DEBUG_TRACE -- routine flow tracking\n" 448239903Sken"-S CAM_DEBUG_SUBTRACE -- internal routine command flow\n" 448346581Sken"-c CAM_DEBUG_CDB -- print out SCSI CDBs only\n" 448446581Sken"tags arguments:\n" 448546581Sken"-N tags specify the number of tags to use for this device\n" 448646581Sken"-q be quiet, don't report the number of tags\n" 448746581Sken"-v report a number of tag-related parameters\n" 448846581Sken"negotiate arguments:\n" 448946581Sken"-a send a test unit ready after negotiation\n" 449046581Sken"-c report/set current negotiation settings\n" 449146581Sken"-D <arg> \"enable\" or \"disable\" disconnection\n" 4492199821Smav"-M mode set ATA mode\n" 449346581Sken"-O offset set command delay offset\n" 449446581Sken"-q be quiet, don't report anything\n" 449546581Sken"-R syncrate synchronization rate in MHz\n" 449646581Sken"-T <arg> \"enable\" or \"disable\" tagged queueing\n" 449746581Sken"-U report/set user negotiation settings\n" 449846581Sken"-W bus_width set the bus width in bits (8, 16 or 32)\n" 449960767Sken"-v also print a Path Inquiry CCB for the controller\n" 450060767Sken"format arguments:\n" 450160767Sken"-q be quiet, don't print status messages\n" 4502144134Sken"-r run in report only mode\n" 450360767Sken"-w don't send immediate format command\n" 4504199079Smav"-y don't ask any questions\n" 4505199079Smav"idle/standby arguments:\n" 4506199079Smav"-t <arg> number of seconds before respective state.\n"); 450789471Sjoerg#endif /* MINIMALISTIC */ 450839214Sgibbs} 450939214Sgibbs 4510214321Smavint 451139214Sgibbsmain(int argc, char **argv) 451239214Sgibbs{ 451339214Sgibbs int c; 451439214Sgibbs char *device = NULL; 451539214Sgibbs int unit = 0; 451639214Sgibbs struct cam_device *cam_dev = NULL; 451739214Sgibbs int timeout = 0, retry_count = 1; 451839214Sgibbs camcontrol_optret optreturn; 451939214Sgibbs char *tstr; 4520118478Sjohan const char *mainopt = "C:En:t:u:v"; 4521118478Sjohan const char *subopt = NULL; 452239214Sgibbs char combinedopt[256]; 452346938Sken int error = 0, optstart = 2; 452446938Sken int devopen = 1; 4525118478Sjohan#ifndef MINIMALISTIC 4526118478Sjohan int bus, target, lun; 4527118478Sjohan#endif /* MINIMALISTIC */ 452839214Sgibbs 4529103092Smdodd cmdlist = CAM_CMD_NONE; 453039214Sgibbs arglist = CAM_ARG_NONE; 453139214Sgibbs 453239214Sgibbs if (argc < 2) { 453346938Sken usage(0); 453439214Sgibbs exit(1); 453539214Sgibbs } 453639214Sgibbs 453739214Sgibbs /* 453839214Sgibbs * Get the base option. 453939214Sgibbs */ 4540103092Smdodd optreturn = getoption(argv[1], &cmdlist, &arglist, &subopt); 454139214Sgibbs 454239214Sgibbs if (optreturn == CC_OR_AMBIGUOUS) { 454339214Sgibbs warnx("ambiguous option %s", argv[1]); 454446938Sken usage(0); 454539214Sgibbs exit(1); 454639214Sgibbs } else if (optreturn == CC_OR_NOT_FOUND) { 454739214Sgibbs warnx("option %s not found", argv[1]); 454846938Sken usage(0); 454939214Sgibbs exit(1); 455039214Sgibbs } 455139214Sgibbs 455239214Sgibbs /* 455339214Sgibbs * Ahh, getopt(3) is a pain. 455439214Sgibbs * 455539214Sgibbs * This is a gross hack. There really aren't many other good 455639214Sgibbs * options (excuse the pun) for parsing options in a situation like 455739214Sgibbs * this. getopt is kinda braindead, so you end up having to run 455839214Sgibbs * through the options twice, and give each invocation of getopt 455939214Sgibbs * the option string for the other invocation. 4560214321Smav * 456139214Sgibbs * You would think that you could just have two groups of options. 456239214Sgibbs * The first group would get parsed by the first invocation of 456339214Sgibbs * getopt, and the second group would get parsed by the second 456439214Sgibbs * invocation of getopt. It doesn't quite work out that way. When 456539214Sgibbs * the first invocation of getopt finishes, it leaves optind pointing 456639214Sgibbs * to the argument _after_ the first argument in the second group. 456739214Sgibbs * So when the second invocation of getopt comes around, it doesn't 456839214Sgibbs * recognize the first argument it gets and then bails out. 4569214321Smav * 457039214Sgibbs * A nice alternative would be to have a flag for getopt that says 457139214Sgibbs * "just keep parsing arguments even when you encounter an unknown 457239214Sgibbs * argument", but there isn't one. So there's no real clean way to 457339214Sgibbs * easily parse two sets of arguments without having one invocation 457439214Sgibbs * of getopt know about the other. 4575214321Smav * 457639214Sgibbs * Without this hack, the first invocation of getopt would work as 457739214Sgibbs * long as the generic arguments are first, but the second invocation 457839214Sgibbs * (in the subfunction) would fail in one of two ways. In the case 457939214Sgibbs * where you don't set optreset, it would fail because optind may be 458039214Sgibbs * pointing to the argument after the one it should be pointing at. 458139214Sgibbs * In the case where you do set optreset, and reset optind, it would 458239214Sgibbs * fail because getopt would run into the first set of options, which 458339214Sgibbs * it doesn't understand. 458439214Sgibbs * 458539214Sgibbs * All of this would "sort of" work if you could somehow figure out 458639214Sgibbs * whether optind had been incremented one option too far. The 458739214Sgibbs * mechanics of that, however, are more daunting than just giving 458839214Sgibbs * both invocations all of the expect options for either invocation. 4589214321Smav * 459039214Sgibbs * Needless to say, I wouldn't mind if someone invented a better 459139214Sgibbs * (non-GPL!) command line parsing interface than getopt. I 459239214Sgibbs * wouldn't mind if someone added more knobs to getopt to make it 459339214Sgibbs * work better. Who knows, I may talk myself into doing it someday, 459439214Sgibbs * if the standards weenies let me. As it is, it just leads to 459539214Sgibbs * hackery like this and causes people to avoid it in some cases. 4596214321Smav * 459739214Sgibbs * KDM, September 8th, 1998 459839214Sgibbs */ 459939214Sgibbs if (subopt != NULL) 460039214Sgibbs sprintf(combinedopt, "%s%s", mainopt, subopt); 460139214Sgibbs else 460239214Sgibbs sprintf(combinedopt, "%s", mainopt); 460339214Sgibbs 460439214Sgibbs /* 460546938Sken * For these options we do not parse optional device arguments and 460646938Sken * we do not open a passthrough device. 460739214Sgibbs */ 4608103092Smdodd if ((cmdlist == CAM_CMD_RESCAN) 4609103092Smdodd || (cmdlist == CAM_CMD_RESET) 4610103092Smdodd || (cmdlist == CAM_CMD_DEVTREE) 4611103092Smdodd || (cmdlist == CAM_CMD_USAGE) 4612103092Smdodd || (cmdlist == CAM_CMD_DEBUG)) 461346938Sken devopen = 0; 461439214Sgibbs 461589471Sjoerg#ifndef MINIMALISTIC 461646938Sken if ((devopen == 1) 461746938Sken && (argc > 2 && argv[2][0] != '-')) { 461846938Sken char name[30]; 461946938Sken int rv; 462046938Sken 4621214073Sbrucec if (isdigit(argv[2][0])) { 462246938Sken /* device specified as bus:target[:lun] */ 462346938Sken rv = parse_btl(argv[2], &bus, &target, &lun, &arglist); 462446938Sken if (rv < 2) 462546938Sken errx(1, "numeric device specification must " 462646938Sken "be either bus:target, or " 462746938Sken "bus:target:lun"); 4628126514Sken /* default to 0 if lun was not specified */ 4629126514Sken if ((arglist & CAM_ARG_LUN) == 0) { 4630126514Sken lun = 0; 4631126514Sken arglist |= CAM_ARG_LUN; 4632126514Sken } 463346938Sken optstart++; 463446938Sken } else { 463546938Sken if (cam_get_device(argv[2], name, sizeof name, &unit) 463646938Sken == -1) 463746938Sken errx(1, "%s", cam_errbuf); 463846938Sken device = strdup(name); 463946938Sken arglist |= CAM_ARG_DEVICE | CAM_ARG_UNIT; 464046938Sken optstart++; 464146938Sken } 464246938Sken } 464389471Sjoerg#endif /* MINIMALISTIC */ 464439214Sgibbs /* 464546938Sken * Start getopt processing at argv[2/3], since we've already 464646938Sken * accepted argv[1..2] as the command name, and as a possible 464746938Sken * device name. 464846938Sken */ 464946938Sken optind = optstart; 465046938Sken 465146938Sken /* 465239214Sgibbs * Now we run through the argument list looking for generic 465339214Sgibbs * options, and ignoring options that possibly belong to 465439214Sgibbs * subfunctions. 465539214Sgibbs */ 465639214Sgibbs while ((c = getopt(argc, argv, combinedopt))!= -1){ 465739214Sgibbs switch(c) { 465839214Sgibbs case 'C': 465939214Sgibbs retry_count = strtol(optarg, NULL, 0); 466039214Sgibbs if (retry_count < 0) 466139214Sgibbs errx(1, "retry count %d is < 0", 466239214Sgibbs retry_count); 466339214Sgibbs arglist |= CAM_ARG_RETRIES; 466439214Sgibbs break; 466539214Sgibbs case 'E': 466639214Sgibbs arglist |= CAM_ARG_ERR_RECOVER; 466739214Sgibbs break; 466839214Sgibbs case 'n': 466939214Sgibbs arglist |= CAM_ARG_DEVICE; 467039214Sgibbs tstr = optarg; 467139214Sgibbs while (isspace(*tstr) && (*tstr != '\0')) 467239214Sgibbs tstr++; 467339214Sgibbs device = (char *)strdup(tstr); 467439214Sgibbs break; 467539214Sgibbs case 't': 467639214Sgibbs timeout = strtol(optarg, NULL, 0); 467739214Sgibbs if (timeout < 0) 467839214Sgibbs errx(1, "invalid timeout %d", timeout); 467939214Sgibbs /* Convert the timeout from seconds to ms */ 468039214Sgibbs timeout *= 1000; 468139214Sgibbs arglist |= CAM_ARG_TIMEOUT; 468239214Sgibbs break; 468339214Sgibbs case 'u': 468439214Sgibbs arglist |= CAM_ARG_UNIT; 468539214Sgibbs unit = strtol(optarg, NULL, 0); 468639214Sgibbs break; 468739214Sgibbs case 'v': 468839214Sgibbs arglist |= CAM_ARG_VERBOSE; 468939214Sgibbs break; 469039214Sgibbs default: 469139214Sgibbs break; 469239214Sgibbs } 469339214Sgibbs } 469439214Sgibbs 469589471Sjoerg#ifndef MINIMALISTIC 469639214Sgibbs /* 469739214Sgibbs * For most commands we'll want to open the passthrough device 469839214Sgibbs * associated with the specified device. In the case of the rescan 469939214Sgibbs * commands, we don't use a passthrough device at all, just the 470039214Sgibbs * transport layer device. 470139214Sgibbs */ 470246938Sken if (devopen == 1) { 470361233Sken if (((arglist & (CAM_ARG_BUS|CAM_ARG_TARGET)) == 0) 470461233Sken && (((arglist & CAM_ARG_DEVICE) == 0) 470561233Sken || ((arglist & CAM_ARG_UNIT) == 0))) { 470661233Sken errx(1, "subcommand \"%s\" requires a valid device " 470761233Sken "identifier", argv[1]); 470861233Sken } 470961233Sken 471046938Sken if ((cam_dev = ((arglist & (CAM_ARG_BUS | CAM_ARG_TARGET))? 471146938Sken cam_open_btl(bus, target, lun, O_RDWR, NULL) : 471246938Sken cam_open_spec_device(device,unit,O_RDWR,NULL))) 471346938Sken == NULL) 471439214Sgibbs errx(1,"%s", cam_errbuf); 471539214Sgibbs } 471689471Sjoerg#endif /* MINIMALISTIC */ 471739214Sgibbs 471839214Sgibbs /* 471941112Sken * Reset optind to 2, and reset getopt, so these routines can parse 472039214Sgibbs * the arguments again. 472139214Sgibbs */ 472246938Sken optind = optstart; 472339214Sgibbs optreset = 1; 472439214Sgibbs 4725103092Smdodd switch(cmdlist) { 472689471Sjoerg#ifndef MINIMALISTIC 4727103092Smdodd case CAM_CMD_DEVLIST: 472839214Sgibbs error = getdevlist(cam_dev); 472939214Sgibbs break; 473089521Sjoerg#endif /* MINIMALISTIC */ 4731103092Smdodd case CAM_CMD_DEVTREE: 473239214Sgibbs error = getdevtree(); 473339214Sgibbs break; 473489521Sjoerg#ifndef MINIMALISTIC 4735103092Smdodd case CAM_CMD_TUR: 473646581Sken error = testunitready(cam_dev, retry_count, timeout, 0); 473739214Sgibbs break; 4738103092Smdodd case CAM_CMD_INQUIRY: 473939214Sgibbs error = scsidoinquiry(cam_dev, argc, argv, combinedopt, 474039214Sgibbs retry_count, timeout); 474139214Sgibbs break; 4742195534Sscottl case CAM_CMD_IDENTIFY: 4743195534Sscottl error = ataidentify(cam_dev, retry_count, timeout); 4744195534Sscottl break; 4745103092Smdodd case CAM_CMD_STARTSTOP: 474639214Sgibbs error = scsistart(cam_dev, arglist & CAM_ARG_START_UNIT, 474739214Sgibbs arglist & CAM_ARG_EJECT, retry_count, 474839214Sgibbs timeout); 474939214Sgibbs break; 475089471Sjoerg#endif /* MINIMALISTIC */ 4751103092Smdodd case CAM_CMD_RESCAN: 475241962Smjacob error = dorescan_or_reset(argc, argv, 1); 475339214Sgibbs break; 4754103092Smdodd case CAM_CMD_RESET: 475541962Smjacob error = dorescan_or_reset(argc, argv, 0); 475641962Smjacob break; 475789471Sjoerg#ifndef MINIMALISTIC 4758103092Smdodd case CAM_CMD_READ_DEFECTS: 475939214Sgibbs error = readdefects(cam_dev, argc, argv, combinedopt, 476039214Sgibbs retry_count, timeout); 476139214Sgibbs break; 4762103092Smdodd case CAM_CMD_MODE_PAGE: 476339214Sgibbs modepage(cam_dev, argc, argv, combinedopt, 476439214Sgibbs retry_count, timeout); 476539214Sgibbs break; 4766103092Smdodd case CAM_CMD_SCSI_CMD: 476739214Sgibbs error = scsicmd(cam_dev, argc, argv, combinedopt, 476839214Sgibbs retry_count, timeout); 476939214Sgibbs break; 4770103092Smdodd case CAM_CMD_DEBUG: 477139214Sgibbs error = camdebug(argc, argv, combinedopt); 477239214Sgibbs break; 4773103092Smdodd case CAM_CMD_TAG: 477446581Sken error = tagcontrol(cam_dev, argc, argv, combinedopt); 477546581Sken break; 4776103092Smdodd case CAM_CMD_RATE: 477746581Sken error = ratecontrol(cam_dev, retry_count, timeout, 477846581Sken argc, argv, combinedopt); 477946581Sken break; 4780103092Smdodd case CAM_CMD_FORMAT: 478160767Sken error = scsiformat(cam_dev, argc, argv, 478260767Sken combinedopt, retry_count, timeout); 478360767Sken break; 4784161506Sken case CAM_CMD_REPORTLUNS: 4785161506Sken error = scsireportluns(cam_dev, argc, argv, 4786161506Sken combinedopt, retry_count, 4787161506Sken timeout); 4788161506Sken break; 4789172093Sken case CAM_CMD_READCAP: 4790172093Sken error = scsireadcapacity(cam_dev, argc, argv, 4791172093Sken combinedopt, retry_count, 4792172093Sken timeout); 4793172093Sken break; 4794199079Smav case CAM_CMD_IDLE: 4795199079Smav case CAM_CMD_STANDBY: 4796199079Smav case CAM_CMD_SLEEP: 4797199079Smav error = atapm(cam_dev, argc, argv, 4798199079Smav combinedopt, retry_count, 4799199079Smav timeout); 4800199079Smav break; 480189471Sjoerg#endif /* MINIMALISTIC */ 4802103092Smdodd case CAM_CMD_USAGE: 480346938Sken usage(1); 480446938Sken break; 480539214Sgibbs default: 480646938Sken usage(0); 480739214Sgibbs error = 1; 480839214Sgibbs break; 480939214Sgibbs } 481039214Sgibbs 481139214Sgibbs if (cam_dev != NULL) 481239214Sgibbs cam_close_device(cam_dev); 481339214Sgibbs 481439214Sgibbs exit(error); 481539214Sgibbs} 4816