1/* Copyright 1996 Grant R. Guenther, based on work of Itai Nahshon 2 * http://www.torque.net/ziptool.html 3 * Copyright 1997-1999,2001,2002,2005,2007,2009 Alain Knaff. 4 * This file is part of mtools. 5 * 6 * Mtools is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * Mtools is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with Mtools. If not, see <http://www.gnu.org/licenses/>. 18 * 19 * scsi.c 20 * Iomega Zip/Jaz drive tool 21 * change protection mode and eject disk 22 */ 23 24/* scis.c by Markus Gyger <mgyger@itr.ch> */ 25/* This code is based on ftp://gear.torque.net/pub/ziptool.c */ 26/* by Grant R. Guenther with the following copyright notice: */ 27 28/* (c) 1996 Grant R. Guenther, based on work of Itai Nahshon */ 29/* http://www.torque.net/ziptool.html */ 30 31 32/* A.K. Moved this from mzip.c to a separate file in order to share with 33 * plain_io.c */ 34 35#include "sysincludes.h" 36#include "mtools.h" 37#include "scsi.h" 38 39#if defined OS_hpux 40#include <sys/scsi.h> 41#endif 42 43#ifdef OS_solaris 44#include <sys/scsi/scsi.h> 45#endif /* solaris */ 46 47#ifdef OS_sunos 48#include <scsi/generic/commands.h> 49#include <scsi/impl/uscsi.h> 50#endif /* sunos */ 51 52#ifdef sgi 53#include <sys/dsreq.h> 54#endif 55 56#ifdef OS_linux 57#define SCSI_IOCTL_SEND_COMMAND 1 58struct scsi_ioctl_command { 59 int inlen; 60 int outlen; 61 char cmd[5008]; 62}; 63#endif 64 65#ifdef _SCO_DS 66#include <sys/scsicmd.h> 67#endif 68 69#if (defined(OS_freebsd)) && (__FreeBSD__ >= 2) 70#include <camlib.h> 71#endif 72 73#if defined(OS_netbsd) || defined(OS_netbsdelf) 74#include <sys/scsiio.h> 75#endif 76 77int scsi_max_length(void) 78{ 79#ifdef OS_linux 80 return 8; 81#else 82 return 255; 83#endif 84} 85 86int scsi_open(const char *name, int flag, int mode, void **extra_data) 87{ 88#if (defined(OS_freebsd)) && (__FreeBSD__ >= 2) 89 struct cam_device *cam_dev; 90 cam_dev = cam_open_device(name, O_RDWR); 91 *extra_data = (void *) cam_dev; 92 if (cam_dev) 93 return cam_dev->fd; 94 else 95 return -1; 96#else 97 return open(name, O_RDONLY | O_LARGEFILE | O_BINARY 98#ifdef O_NDELAY 99 | O_NDELAY 100#endif 101 /* O_RDONLY | dev->mode*/); 102#endif 103} 104 105int scsi_cmd(int fd, unsigned char *cdb, int cmdlen, scsi_io_mode_t mode, 106 void *data, size_t len, void *extra_data) 107{ 108#if defined OS_hpux 109 struct sctl_io sctl_io; 110 111 memset(&sctl_io, 0, sizeof sctl_io); /* clear reserved fields */ 112 memcpy(sctl_io.cdb, cdb, cmdlen); /* copy command */ 113 sctl_io.cdb_length = cmdlen; /* command length */ 114 sctl_io.max_msecs = 2000; /* allow 2 seconds for cmd */ 115 116 switch (mode) { 117 case SCSI_IO_READ: 118 sctl_io.flags = SCTL_READ; 119 sctl_io.data_length = len; 120 sctl_io.data = data; 121 break; 122 case SCSI_IO_WRITE: 123 sctl_io.flags = 0; 124 sctl_io.data_length = data ? len : 0; 125 sctl_io.data = len ? data : 0; 126 break; 127 } 128 129 if (ioctl(fd, SIOC_IO, &sctl_io) == -1) { 130 perror("scsi_io"); 131 return -1; 132 } 133 134 return sctl_io.cdb_status; 135 136#elif defined OS_sunos || defined OS_solaris 137 struct uscsi_cmd uscsi_cmd; 138 memset(&uscsi_cmd, 0, sizeof uscsi_cmd); 139 uscsi_cmd.uscsi_cdb = (char *)cdb; 140 uscsi_cmd.uscsi_cdblen = cmdlen; 141#ifdef OS_solaris 142 uscsi_cmd.uscsi_timeout = 20; /* msec? */ 143#endif /* solaris */ 144 145 uscsi_cmd.uscsi_buflen = (u_int)len; 146 uscsi_cmd.uscsi_bufaddr = data; 147 148 switch (mode) { 149 case SCSI_IO_READ: 150 uscsi_cmd.uscsi_flags = USCSI_READ; 151 break; 152 case SCSI_IO_WRITE: 153 uscsi_cmd.uscsi_flags = USCSI_WRITE; 154 break; 155 } 156 157 if (ioctl(fd, USCSICMD, &uscsi_cmd) == -1) { 158 perror("scsi_io"); 159 return -1; 160 } 161 162 if(uscsi_cmd.uscsi_status) { 163 errno = 0; 164 fprintf(stderr,"scsi status=%x\n", 165 (unsigned short)uscsi_cmd.uscsi_status); 166 return -1; 167 } 168 169 return 0; 170 171#elif defined OS_linux 172 struct scsi_ioctl_command my_scsi_cmd; 173 174 175 memcpy(my_scsi_cmd.cmd, cdb, cmdlen); /* copy command */ 176 177 switch (mode) { 178 case SCSI_IO_READ: 179 my_scsi_cmd.inlen = 0; 180 my_scsi_cmd.outlen = len; 181 break; 182 case SCSI_IO_WRITE: 183 my_scsi_cmd.inlen = len; 184 my_scsi_cmd.outlen = 0; 185 memcpy(my_scsi_cmd.cmd + cmdlen,data,len); 186 break; 187 } 188 189 if (ioctl(fd, SCSI_IOCTL_SEND_COMMAND, &my_scsi_cmd) < 0) { 190 perror("scsi_io"); 191 return -1; 192 } 193 194 switch (mode) { 195 case SCSI_IO_READ: 196 memcpy(data, &my_scsi_cmd.cmd[0], len); 197 break; 198 case SCSI_IO_WRITE: 199 break; 200 } 201 202 return 0; /* where to get scsi status? */ 203 204#elif (defined _SCO_DS) && (defined SCSIUSERCMD) 205 struct scsicmd my_scsi_cmd; 206 207 memset(my_scsi_cmd.cdb, 0, SCSICMDLEN); /* ensure zero pad */ 208 memcpy(my_scsi_cmd.cdb, cdb, cmdlen); 209 my_scsi_cmd.cdb_len = cmdlen; 210 my_scsi_cmd.data_len = len; 211 my_scsi_cmd.data_ptr = data; 212 my_scsi_cmd.is_write = mode == SCSI_IO_WRITE; 213 if (ioctl(fd,SCSIUSERCMD,&my_scsi_cmd) == -1) { 214 perror("scsi_io: SCSIUSERCMD"); 215 return -1; 216 } 217 if (my_scsi_cmd.host_sts != 0 || my_scsi_cmd.target_sts != 0) { 218 fprintf(stderr, "scsi_io: scsi status: host=%x; target=%x\n", 219 (unsigned)my_scsi_cmd.host_sts,(unsigned)my_scsi_cmd.target_sts); 220 return -1; 221 } 222 return 0; 223#elif defined sgi 224 struct dsreq my_scsi_cmd; 225 226 my_scsi_cmd.ds_cmdbuf = (char *)cdb; 227 my_scsi_cmd.ds_cmdlen = cmdlen; 228 my_scsi_cmd.ds_databuf = data; 229 my_scsi_cmd.ds_datalen = len; 230 switch (mode) { 231 case SCSI_IO_READ: 232 my_scsi_cmd.ds_flags = DSRQ_READ|DSRQ_SENSE; 233 break; 234 case SCSI_IO_WRITE: 235 my_scsi_cmd.ds_flags = DSRQ_WRITE|DSRQ_SENSE; 236 break; 237 } 238 my_scsi_cmd.ds_time = 10000; 239 my_scsi_cmd.ds_link = 0; 240 my_scsi_cmd.ds_synch =0; 241 my_scsi_cmd.ds_ret =0; 242 if (ioctl(fd, DS_ENTER, &my_scsi_cmd) == -1) { 243 perror("scsi_io"); 244 return -1; 245 } 246 247 if(my_scsi_cmd.ds_status) { 248 errno = 0; 249 fprintf(stderr,"scsi status=%x\n", 250 (unsigned short)my_scsi_cmd.ds_status); 251 return -1; 252 } 253 254 return 0; 255#elif (defined OS_freebsd) && (__FreeBSD__ >= 2) 256#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */ 257 union ccb *ccb; 258 int flags; 259 int r; 260 struct cam_device *cam_dev = (struct cam_device *) extra_data; 261 262 263 if (cam_dev==NULL || cam_dev->fd!=fd) 264 { 265 fprintf(stderr,"invalid file descriptor\n"); 266 return -1; 267 } 268 ccb = cam_getccb(cam_dev); 269 270 bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cmdlen); 271 272 if (mode == SCSI_IO_READ) 273 flags = CAM_DIR_IN; 274 else if (data && len) 275 flags = CAM_DIR_OUT; 276 else 277 flags = CAM_DIR_NONE; 278 cam_fill_csio(&ccb->csio, 279 /* retry */ 1, 280 /* cbfcnp */ NULL, 281 flags, 282 /* tag_action */ MSG_SIMPLE_Q_TAG, 283 /*data_ptr*/ len ? data : 0, 284 /*data_len */ data ? len : 0, 285 96, 286 cmdlen, 287 5000); 288 289 if (cam_send_ccb(cam_dev, ccb) < 0 || 290 (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 291 return -1; 292 } 293 return 0; 294#elif defined(OS_netbsd) || defined(OS_netbsdelf) 295 struct scsireq sc; 296 297 memset(&sc, 0, sizeof(sc)); 298 memcpy(sc.cmd, cdb, cmdlen); 299 sc.cmdlen = cmdlen; 300 sc.databuf = data; 301 sc.datalen = len; 302 sc.senselen = 0; 303 sc.timeout = 10000; 304 switch (mode) { 305 case SCSI_IO_READ: 306 sc.flags = SCCMD_READ; 307 break; 308 case SCSI_IO_WRITE: 309 sc.flags = SCCMD_WRITE; 310 break; 311 } 312 313 if (ioctl(fd, SCIOCCOMMAND, &sc) == -1) { 314 perror("SCIOCCOMMAND ioctl"); 315 return -1; 316 } 317 318 if (sc.retsts) { 319 errno = EIO; 320 fprintf(stderr, "SCSI command failed, retsts %d\n", 321sc.retsts); 322 return -1; 323 } 324 325 return 0; 326#else 327 fprintf(stderr, "scsi_io not implemented\n"); 328 return -1; 329#endif 330} 331