blob: 114eb8c409d3d0152b732a8ca37e6b58affac524 [file] [log] [blame]
Alistair Delvabeaee832021-02-24 11:27:23 -08001/* 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#include <scsi/scsi.h>
58#include <scsi/sg.h>
59#endif
60
61#ifdef _SCO_DS
62#include <sys/scsicmd.h>
63#endif
64
65#if (defined(OS_freebsd)) && (__FreeBSD__ >= 2)
66#include <camlib.h>
67#endif
68
69#if defined(OS_netbsd) || defined(OS_netbsdelf)
70#include <sys/scsiio.h>
71#endif
72
Yi Kong39bbd962022-01-09 19:41:38 +080073unsigned int scsi_max_length(void)
Alistair Delvabeaee832021-02-24 11:27:23 -080074{
75#ifdef OS_linux
76 return 8;
77#else
78 return 255;
79#endif
80}
81
82int scsi_open(const char *name, int flag UNUSEDP, int mode UNUSEDP,
83 void **extra_data UNUSEDP)
84{
85#if (defined(OS_freebsd)) && (__FreeBSD__ >= 2)
86 struct cam_device *cam_dev;
87 cam_dev = cam_open_device(name, O_RDWR);
88 *extra_data = (void *) cam_dev;
89 if (cam_dev)
90 return cam_dev->fd;
91 else
92 return -1;
93#else
94 return open(name, O_RDONLY | O_LARGEFILE | O_BINARY
95#ifdef O_NDELAY
96 | O_NDELAY
97#endif
98 /* O_RDONLY | dev->mode*/);
99#endif
100}
101
Yi Kong39bbd962022-01-09 19:41:38 +0800102int scsi_cmd(int fd, unsigned char *cdb, uint8_t cmdlen, scsi_io_mode_t mode,
103 void *data, uint32_t len, void *extra_data UNUSEDP)
Alistair Delvabeaee832021-02-24 11:27:23 -0800104{
105#if defined OS_hpux
106 struct sctl_io sctl_io;
Yi Kong39bbd962022-01-09 19:41:38 +0800107
Alistair Delvabeaee832021-02-24 11:27:23 -0800108 memset(&sctl_io, 0, sizeof sctl_io); /* clear reserved fields */
109 memcpy(sctl_io.cdb, cdb, cmdlen); /* copy command */
110 sctl_io.cdb_length = cmdlen; /* command length */
111 sctl_io.max_msecs = 2000; /* allow 2 seconds for cmd */
112
113 switch (mode) {
114 case SCSI_IO_READ:
115 sctl_io.flags = SCTL_READ;
116 sctl_io.data_length = len;
117 sctl_io.data = data;
118 break;
Yi Kong39bbd962022-01-09 19:41:38 +0800119 case SCSI_IO_WRITE:
Alistair Delvabeaee832021-02-24 11:27:23 -0800120 sctl_io.flags = 0;
121 sctl_io.data_length = data ? len : 0;
122 sctl_io.data = len ? data : 0;
123 break;
124 }
125
126 if (ioctl(fd, SIOC_IO, &sctl_io) == -1) {
127 perror("scsi_io");
128 return -1;
129 }
130
131 return sctl_io.cdb_status;
Yi Kong39bbd962022-01-09 19:41:38 +0800132
Alistair Delvabeaee832021-02-24 11:27:23 -0800133#elif defined OS_sunos || defined OS_solaris
134 struct uscsi_cmd uscsi_cmd;
135 memset(&uscsi_cmd, 0, sizeof uscsi_cmd);
136 uscsi_cmd.uscsi_cdb = (char *)cdb;
137 uscsi_cmd.uscsi_cdblen = cmdlen;
138#ifdef OS_solaris
139 uscsi_cmd.uscsi_timeout = 20; /* msec? */
140#endif /* solaris */
Yi Kong39bbd962022-01-09 19:41:38 +0800141
Alistair Delvabeaee832021-02-24 11:27:23 -0800142 uscsi_cmd.uscsi_buflen = (u_int)len;
143 uscsi_cmd.uscsi_bufaddr = data;
144
145 switch (mode) {
146 case SCSI_IO_READ:
147 uscsi_cmd.uscsi_flags = USCSI_READ;
148 break;
149 case SCSI_IO_WRITE:
150 uscsi_cmd.uscsi_flags = USCSI_WRITE;
151 break;
152 }
153
154 if (ioctl(fd, USCSICMD, &uscsi_cmd) == -1) {
155 perror("scsi_io");
156 return -1;
157 }
158
159 if(uscsi_cmd.uscsi_status) {
160 errno = 0;
Yi Kong39bbd962022-01-09 19:41:38 +0800161 fprintf(stderr,"scsi status=%x\n",
Alistair Delvabeaee832021-02-24 11:27:23 -0800162 (unsigned short)uscsi_cmd.uscsi_status);
163 return -1;
164 }
Yi Kong39bbd962022-01-09 19:41:38 +0800165
Alistair Delvabeaee832021-02-24 11:27:23 -0800166 return 0;
Yi Kong39bbd962022-01-09 19:41:38 +0800167
Alistair Delvabeaee832021-02-24 11:27:23 -0800168#elif defined OS_linux
169 struct sg_io_hdr my_scsi_cmd;
170
171 /*
172 ** Init the command
173 */
174 memset(&my_scsi_cmd,0,sizeof(my_scsi_cmd));
175 my_scsi_cmd.interface_id = 'S';
176 my_scsi_cmd.dxfer_direction = (mode == SCSI_IO_READ)?(SG_DXFER_FROM_DEV):(SG_DXFER_TO_DEV);
177 my_scsi_cmd.cmd_len = cmdlen;
178 my_scsi_cmd.mx_sb_len = 0;
179 my_scsi_cmd.dxfer_len = len;
180 my_scsi_cmd.dxferp = data;
181 my_scsi_cmd.cmdp = cdb;
Yi Kong39bbd962022-01-09 19:41:38 +0800182 my_scsi_cmd.timeout = ~0u; /* where is MAX_UINT defined??? */
Alistair Delvabeaee832021-02-24 11:27:23 -0800183
184#ifdef DEBUG
185 printf("CMD(%d): %02x%02x%02x%02x%02x%02x %sdevice\n",cmdlen,cdb[0],cdb[1],cdb[2],cdb[3],cdb[4],cdb[5],
186 (mode==SCSI_IO_READ)?("<-"):("->"));
187 printf("DATA : len = %d\n",len);
188#endif
189
190 if (ioctl(fd, SG_IO,&my_scsi_cmd) < 0) {
191 perror("scsi_io");
192 return -1;
193 }
Yi Kong39bbd962022-01-09 19:41:38 +0800194
Alistair Delvabeaee832021-02-24 11:27:23 -0800195 return my_scsi_cmd.status & STATUS_MASK;
196
197#elif (defined _SCO_DS) && (defined SCSIUSERCMD)
198 struct scsicmd my_scsi_cmd;
199
200 memset(my_scsi_cmd.cdb, 0, SCSICMDLEN); /* ensure zero pad */
201 memcpy(my_scsi_cmd.cdb, cdb, cmdlen);
202 my_scsi_cmd.cdb_len = cmdlen;
203 my_scsi_cmd.data_len = len;
204 my_scsi_cmd.data_ptr = data;
205 my_scsi_cmd.is_write = mode == SCSI_IO_WRITE;
206 if (ioctl(fd,SCSIUSERCMD,&my_scsi_cmd) == -1) {
207 perror("scsi_io: SCSIUSERCMD");
208 return -1;
209 }
210 if (my_scsi_cmd.host_sts != 0 || my_scsi_cmd.target_sts != 0) {
211 fprintf(stderr, "scsi_io: scsi status: host=%x; target=%x\n",
212 (unsigned)my_scsi_cmd.host_sts,(unsigned)my_scsi_cmd.target_sts);
213 return -1;
214 }
215 return 0;
216#elif defined sgi
217 struct dsreq my_scsi_cmd;
218
219 my_scsi_cmd.ds_cmdbuf = (char *)cdb;
220 my_scsi_cmd.ds_cmdlen = cmdlen;
221 my_scsi_cmd.ds_databuf = data;
222 my_scsi_cmd.ds_datalen = len;
223 switch (mode) {
224 case SCSI_IO_READ:
225 my_scsi_cmd.ds_flags = DSRQ_READ|DSRQ_SENSE;
226 break;
227 case SCSI_IO_WRITE:
228 my_scsi_cmd.ds_flags = DSRQ_WRITE|DSRQ_SENSE;
229 break;
Yi Kong39bbd962022-01-09 19:41:38 +0800230 }
Alistair Delvabeaee832021-02-24 11:27:23 -0800231 my_scsi_cmd.ds_time = 10000;
232 my_scsi_cmd.ds_link = 0;
233 my_scsi_cmd.ds_synch =0;
234 my_scsi_cmd.ds_ret =0;
235 if (ioctl(fd, DS_ENTER, &my_scsi_cmd) == -1) {
236 perror("scsi_io");
237 return -1;
238 }
239
240 if(my_scsi_cmd.ds_status) {
241 errno = 0;
Yi Kong39bbd962022-01-09 19:41:38 +0800242 fprintf(stderr,"scsi status=%x\n",
Alistair Delvabeaee832021-02-24 11:27:23 -0800243 (unsigned short)my_scsi_cmd.ds_status);
244 return -1;
245 }
Yi Kong39bbd962022-01-09 19:41:38 +0800246
Alistair Delvabeaee832021-02-24 11:27:23 -0800247 return 0;
248#elif (defined OS_freebsd) && (__FreeBSD__ >= 2)
249#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */
250 union ccb *ccb;
251 int flags;
252 int r;
253 struct cam_device *cam_dev = (struct cam_device *) extra_data;
254
255
256 if (cam_dev==NULL || cam_dev->fd!=fd)
257 {
258 fprintf(stderr,"invalid file descriptor\n");
259 return -1;
260 }
261 ccb = cam_getccb(cam_dev);
262
263 bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cmdlen);
264
265 if (mode == SCSI_IO_READ)
266 flags = CAM_DIR_IN;
267 else if (data && len)
268 flags = CAM_DIR_OUT;
269 else
270 flags = CAM_DIR_NONE;
271 cam_fill_csio(&ccb->csio,
272 /* retry */ 1,
273 /* cbfcnp */ NULL,
274 flags,
275 /* tag_action */ MSG_SIMPLE_Q_TAG,
276 /*data_ptr*/ len ? data : 0,
277 /*data_len */ data ? len : 0,
278 96,
279 cmdlen,
280 5000);
Yi Kong39bbd962022-01-09 19:41:38 +0800281
Alistair Delvabeaee832021-02-24 11:27:23 -0800282 if (cam_send_ccb(cam_dev, ccb) < 0 ||
283 (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
284 return -1;
285 }
286 return 0;
287#elif defined(OS_netbsd) || defined(OS_netbsdelf)
288 struct scsireq sc;
289
290 memset(&sc, 0, sizeof(sc));
291 memcpy(sc.cmd, cdb, cmdlen);
292 sc.cmdlen = cmdlen;
293 sc.databuf = data;
294 sc.datalen = len;
295 sc.senselen = 0;
296 sc.timeout = 10000;
297 switch (mode) {
298 case SCSI_IO_READ:
299 sc.flags = SCCMD_READ;
300 break;
301 case SCSI_IO_WRITE:
302 sc.flags = SCCMD_WRITE;
303 break;
304 }
305
306 if (ioctl(fd, SCIOCCOMMAND, &sc) == -1) {
307 perror("SCIOCCOMMAND ioctl");
308 return -1;
309 }
310
311 if (sc.retsts) {
312 errno = EIO;
Yi Kong39bbd962022-01-09 19:41:38 +0800313 fprintf(stderr, "SCSI command failed, retsts %d\n",
Alistair Delvabeaee832021-02-24 11:27:23 -0800314sc.retsts);
315 return -1;
316 }
317
318 return 0;
319#else
320 fprintf(stderr, "scsi_io not implemented\n");
321 return -1;
322#endif
323}