1/* 2 * This program is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU General Public License as 4 * published by the Free Software Foundation; either version 2 of 5 * the License, or (at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 15 * MA 02111-1307 USA 16 */ 17/* 18 * Copyright (c) 2007 Douglas Gilbert. 19 * All rights reserved. 20 * 21 * Redistribution and use in source and binary forms, with or without 22 * modification, are permitted provided that the following conditions 23 * are met: 24 * 1. Redistributions of source code must retain the above copyright 25 * notice, this list of conditions and the following disclaimer. 26 * 2. Redistributions in binary form must reproduce the above copyright 27 * notice, this list of conditions and the following disclaimer in the 28 * documentation and/or other materials provided with the distribution. 29 * 3. The name of the author may not be used to endorse or promote products 30 * derived from this software without specific prior written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 * 44 */ 45 46/* version 1.00 2007/5/3 */ 47 48#include <stdio.h> 49#include <stdlib.h> 50#include <string.h> 51#include <ctype.h> 52#include <unistd.h> 53#include <errno.h> 54#include <fcntl.h> 55#include <sys/param.h> 56 57/* Solaris headers */ 58#include <sys/scsi/generic/commands.h> 59#include <sys/scsi/generic/status.h> 60#include <sys/scsi/impl/types.h> 61#include <sys/scsi/impl/uscsi.h> 62 63#include "sg_pt.h" 64#include "sg_lib.h" 65 66 67#define DEF_TIMEOUT 60 /* 60 seconds */ 68 69struct sg_pt_solaris_scsi { 70 struct uscsi_cmd uscsi; 71 int max_sense_len; 72 int in_err; 73 int os_err; 74}; 75 76struct sg_pt_base { 77 struct sg_pt_solaris_scsi impl; 78}; 79 80 81 82/* Returns >= 0 if successful. If error in Unix returns negated errno. */ 83int scsi_pt_open_device(const char * device_name, int read_only, 84 int verbose) 85{ 86 int oflags = O_NONBLOCK | O_RDWR; 87 int fd; 88 89 read_only = read_only; /* ignore read_only, suppress warning */ 90 if (verbose > 1) { 91 fprintf(stderr, "open %s with flags=0x%x\n", device_name, oflags); 92 } 93 fd = open(device_name, oflags); 94 if (fd < 0) 95 fd = -errno; 96 return fd; 97} 98 99/* Returns 0 if successful. If error in Unix returns negated errno. */ 100int scsi_pt_close_device(int device_fd) 101{ 102 int res; 103 104 res = close(device_fd); 105 if (res < 0) 106 res = -errno; 107 return res; 108} 109 110 111struct sg_pt_base * construct_scsi_pt_obj() 112{ 113 struct sg_pt_solaris_scsi * ptp; 114 115 ptp = (struct sg_pt_solaris_scsi *) 116 malloc(sizeof(struct sg_pt_solaris_scsi)); 117 if (ptp) { 118 memset(ptp, 0, sizeof(struct sg_pt_solaris_scsi)); 119 ptp->uscsi.uscsi_timeout = DEF_TIMEOUT; 120 ptp->uscsi.uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_RQENABLE; 121 ptp->uscsi.uscsi_timeout = DEF_TIMEOUT; 122 } 123 return (struct sg_pt_base *)ptp; 124} 125 126void destruct_scsi_pt_obj(struct sg_pt_base * vp) 127{ 128 struct sg_pt_solaris_scsi * ptp = &vp->impl; 129 130 if (ptp) 131 free(ptp); 132} 133 134void set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb, 135 int cdb_len) 136{ 137 struct sg_pt_solaris_scsi * ptp = &vp->impl; 138 139 if (ptp->uscsi.uscsi_cdb) 140 ++ptp->in_err; 141 ptp->uscsi.uscsi_cdb = (char *)cdb; 142 ptp->uscsi.uscsi_cdblen = cdb_len; 143} 144 145void set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense, 146 int max_sense_len) 147{ 148 struct sg_pt_solaris_scsi * ptp = &vp->impl; 149 150 if (ptp->uscsi.uscsi_rqbuf) 151 ++ptp->in_err; 152 memset(sense, 0, max_sense_len); 153 ptp->uscsi.uscsi_rqbuf = (char *)sense; 154 ptp->uscsi.uscsi_rqlen = max_sense_len; 155 ptp->max_sense_len = max_sense_len; 156} 157 158void set_scsi_pt_data_in(struct sg_pt_base * vp, /* from device */ 159 unsigned char * dxferp, int dxfer_len) 160{ 161 struct sg_pt_solaris_scsi * ptp = &vp->impl; 162 163 if (ptp->uscsi.uscsi_bufaddr) 164 ++ptp->in_err; 165 if (dxfer_len > 0) { 166 ptp->uscsi.uscsi_bufaddr = (char *)dxferp; 167 ptp->uscsi.uscsi_buflen = dxfer_len; 168 ptp->uscsi.uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_RQENABLE; 169 } 170} 171 172void set_scsi_pt_data_out(struct sg_pt_base * vp, /* to device */ 173 const unsigned char * dxferp, int dxfer_len) 174{ 175 struct sg_pt_solaris_scsi * ptp = &vp->impl; 176 177 if (ptp->uscsi.uscsi_bufaddr) 178 ++ptp->in_err; 179 if (dxfer_len > 0) { 180 ptp->uscsi.uscsi_bufaddr = (char *)dxferp; 181 ptp->uscsi.uscsi_buflen = dxfer_len; 182 ptp->uscsi.uscsi_flags = USCSI_WRITE | USCSI_ISOLATE | USCSI_RQENABLE; 183 } 184} 185 186void set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id) 187{ 188 // struct sg_pt_solaris_scsi * ptp = &vp->impl; 189 190 vp = vp; /* ignore and suppress warning */ 191 pack_id = pack_id; /* ignore and suppress warning */ 192} 193 194void set_scsi_pt_tag(struct sg_pt_base * vp, unsigned long long tag) 195{ 196 // struct sg_pt_solaris_scsi * ptp = &vp->impl; 197 198 vp = vp; /* ignore and suppress warning */ 199 tag = tag; /* ignore and suppress warning */ 200} 201 202/* Note that task management function codes are transport specific */ 203void set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code) 204{ 205 struct sg_pt_solaris_scsi * ptp = &vp->impl; 206 207 ++ptp->in_err; 208 tmf_code = tmf_code; /* dummy to silence compiler */ 209} 210 211void set_scsi_pt_task_attr(struct sg_pt_base * vp, int attribute, 212 int priority) 213{ 214 struct sg_pt_solaris_scsi * ptp = &vp->impl; 215 216 ++ptp->in_err; 217 attribute = attribute; /* dummy to silence compiler */ 218 priority = priority; /* dummy to silence compiler */ 219} 220 221int do_scsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose) 222{ 223 struct sg_pt_solaris_scsi * ptp = &vp->impl; 224 225 if (ptp->in_err) { 226 if (verbose) 227 fprintf(stderr, "Replicated or unused set_scsi_pt... " 228 "functions\n"); 229 return SCSI_PT_DO_BAD_PARAMS; 230 } 231 if (NULL == ptp->uscsi.uscsi_cdb) { 232 if (verbose) 233 fprintf(stderr, "No SCSI command (cdb) given\n"); 234 return SCSI_PT_DO_BAD_PARAMS; 235 } 236 if (time_secs > 0) 237 ptp->uscsi.uscsi_timeout = time_secs; 238 239 if (ioctl(fd, USCSICMD, &ptp->uscsi)) { 240 ptp->os_err = errno; 241 if ((EIO == ptp->os_err) && ptp->uscsi.uscsi_status) { 242 ptp->os_err = 0; 243 return 0; 244 } 245 if (verbose) 246 fprintf(stderr, "ioctl(USCSICMD) failed with os_err " 247 "(errno) = %d\n", ptp->os_err); 248 return -ptp->os_err; 249 } 250 return 0; 251} 252 253int get_scsi_pt_result_category(const struct sg_pt_base * vp) 254{ 255 const struct sg_pt_solaris_scsi * ptp = &vp->impl; 256 int scsi_st = ptp->uscsi.uscsi_status; 257 258 if (ptp->os_err) 259 return SCSI_PT_RESULT_OS_ERR; 260 else if ((SAM_STAT_CHECK_CONDITION == scsi_st) || 261 (SAM_STAT_COMMAND_TERMINATED == scsi_st)) 262 return SCSI_PT_RESULT_SENSE; 263 else if (scsi_st) 264 return SCSI_PT_RESULT_STATUS; 265 else 266 return SCSI_PT_RESULT_GOOD; 267} 268 269int get_scsi_pt_resid(const struct sg_pt_base * vp) 270{ 271 const struct sg_pt_solaris_scsi * ptp = &vp->impl; 272 273 return ptp->uscsi.uscsi_resid; 274} 275 276int get_scsi_pt_status_response(const struct sg_pt_base * vp) 277{ 278 const struct sg_pt_solaris_scsi * ptp = &vp->impl; 279 280 return ptp->uscsi.uscsi_status; 281} 282 283int get_scsi_pt_sense_len(const struct sg_pt_base * vp) 284{ 285 const struct sg_pt_solaris_scsi * ptp = &vp->impl; 286 int res; 287 288 if (ptp->max_sense_len > 0) { 289 res = ptp->max_sense_len - ptp->uscsi.uscsi_rqresid; 290 return (res > 0) ? res : 0; 291 } 292 return 0; 293} 294 295int get_scsi_pt_duration_ms(const struct sg_pt_base * vp) 296{ 297 // const struct sg_pt_solaris_scsi * ptp = &vp->impl; 298 299 vp = vp; /* ignore and suppress warning */ 300 return -1; /* not available */ 301} 302 303int get_scsi_pt_transport_err(const struct sg_pt_base * vp) 304{ 305 // const struct sg_pt_solaris_scsi * ptp = &vp->impl; 306 307 vp = vp; /* ignore and suppress warning */ 308 return 0; 309} 310 311int get_scsi_pt_os_err(const struct sg_pt_base * vp) 312{ 313 const struct sg_pt_solaris_scsi * ptp = &vp->impl; 314 315 return ptp->os_err; 316} 317 318char * get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, 319 int max_b_len, char * b) 320{ 321 // const struct sg_pt_solaris_scsi * ptp = &vp->impl; 322 323 vp = vp; /* ignore and suppress warning */ 324 if (max_b_len > 0) 325 b[0] = '\0'; 326 327 return b; 328} 329 330char * get_scsi_pt_os_err_str(const struct sg_pt_base * vp, 331 int max_b_len, char * b) 332{ 333 const struct sg_pt_solaris_scsi * ptp = &vp->impl; 334 const char * cp; 335 336 cp = safe_strerror(ptp->os_err); 337 strncpy(b, cp, max_b_len); 338 if ((int)strlen(cp) >= max_b_len) 339 b[max_b_len - 1] = '\0'; 340 return b; 341} 342