xref: /aosp_15_r20/external/mtools/scsi.c (revision d5c9a868b113e0ec0db2f27bc2ce8a253e77c4b0)
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