Initial import package mtools: Programs for accessing MS-DOS disks without mounting...
[profile/ivi/mtools.git] / scsi.c
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
58 struct 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
77 int scsi_max_length(void)
78 {
79 #ifdef OS_linux
80         return 8;
81 #else
82         return 255;
83 #endif
84 }
85
86 int 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
105 int 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", 
321 sc.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 }