• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #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 
scsi_max_length(void)73 int scsi_max_length(void)
74 {
75 #ifdef OS_linux
76 	return 8;
77 #else
78 	return 255;
79 #endif
80 }
81 
scsi_open(const char * name,int flag UNUSEDP,int mode UNUSEDP,void ** extra_data UNUSEDP)82 int 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 
scsi_cmd(int fd,unsigned char * cdb,int cmdlen,scsi_io_mode_t mode,void * data,size_t len,void * extra_data UNUSEDP)102 int scsi_cmd(int fd, unsigned char *cdb, int cmdlen, scsi_io_mode_t mode,
103 	     void *data, size_t len, void *extra_data UNUSEDP)
104 {
105 #if defined OS_hpux
106 	struct sctl_io sctl_io;
107 
108 	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;
119 		case SCSI_IO_WRITE:
120 			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;
132 
133 #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 */
141 
142 	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;
161 		fprintf(stderr,"scsi status=%x\n",
162 			(unsigned short)uscsi_cmd.uscsi_status);
163 		return -1;
164 	}
165 
166 	return 0;
167 
168 #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;
182 	my_scsi_cmd.timeout         = ~0; /* where is MAX_UINT defined??? */
183 
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 	}
194 
195 	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;
230         }
231 	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;
242                 fprintf(stderr,"scsi status=%x\n",
243                         (unsigned short)my_scsi_cmd.ds_status);
244                 return -1;
245         }
246 
247         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);
281 
282       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;
313                 fprintf(stderr, "SCSI command failed, retsts %d\n",
314 sc.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 }
324