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