Imported Upstream version 4.0.18
[platform/upstream/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 #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
73 int scsi_max_length(void)
74 {
75 #ifdef OS_linux
76         return 8;
77 #else
78         return 255;
79 #endif
80 }
81
82 int scsi_open(const char *name, int flag, int mode, void **extra_data)
83 {
84 #if (defined(OS_freebsd)) && (__FreeBSD__ >= 2)
85     struct cam_device *cam_dev;
86     cam_dev = cam_open_device(name, O_RDWR);
87     *extra_data = (void *) cam_dev;
88     if (cam_dev)
89         return cam_dev->fd;
90     else
91         return -1;
92 #else
93     return open(name, O_RDONLY | O_LARGEFILE | O_BINARY
94 #ifdef O_NDELAY
95                 | O_NDELAY
96 #endif
97         /* O_RDONLY  | dev->mode*/);
98 #endif
99 }
100
101 int scsi_cmd(int fd, unsigned char *cdb, int cmdlen, scsi_io_mode_t mode,
102              void *data, size_t len, void *extra_data)
103 {
104 #if defined OS_hpux
105         struct sctl_io sctl_io;
106         
107         memset(&sctl_io, 0, sizeof sctl_io);   /* clear reserved fields */
108         memcpy(sctl_io.cdb, cdb, cmdlen);      /* copy command */
109         sctl_io.cdb_length = cmdlen;           /* command length */
110         sctl_io.max_msecs = 2000;              /* allow 2 seconds for cmd */
111
112         switch (mode) {
113                 case SCSI_IO_READ:
114                         sctl_io.flags = SCTL_READ;
115                         sctl_io.data_length = len;
116                         sctl_io.data = data;
117                         break;
118                 case SCSI_IO_WRITE: 
119                         sctl_io.flags = 0;
120                         sctl_io.data_length = data ? len : 0;
121                         sctl_io.data = len ? data : 0;
122                         break;
123         }
124
125         if (ioctl(fd, SIOC_IO, &sctl_io) == -1) {
126                 perror("scsi_io");
127                 return -1;
128         }
129
130         return sctl_io.cdb_status;
131         
132 #elif defined OS_sunos || defined OS_solaris
133         struct uscsi_cmd uscsi_cmd;
134         memset(&uscsi_cmd, 0, sizeof uscsi_cmd);
135         uscsi_cmd.uscsi_cdb = (char *)cdb;
136         uscsi_cmd.uscsi_cdblen = cmdlen;
137 #ifdef OS_solaris
138         uscsi_cmd.uscsi_timeout = 20;  /* msec? */
139 #endif /* solaris */
140         
141         uscsi_cmd.uscsi_buflen = (u_int)len;
142         uscsi_cmd.uscsi_bufaddr = data;
143
144         switch (mode) {
145                 case SCSI_IO_READ:
146                         uscsi_cmd.uscsi_flags = USCSI_READ;
147                         break;
148                 case SCSI_IO_WRITE:
149                         uscsi_cmd.uscsi_flags = USCSI_WRITE;
150                         break;
151         }
152
153         if (ioctl(fd, USCSICMD, &uscsi_cmd) == -1) {
154                 perror("scsi_io");
155                 return -1;
156         }
157
158         if(uscsi_cmd.uscsi_status) {
159                 errno = 0;
160                 fprintf(stderr,"scsi status=%x\n",  
161                         (unsigned short)uscsi_cmd.uscsi_status);
162                 return -1;
163         }
164         
165         return 0;
166         
167 #elif defined OS_linux
168         struct sg_io_hdr my_scsi_cmd;
169
170         /*
171         ** Init the command
172         */
173         memset(&scsi_cmd,0,sizeof(scsi_cmd));
174         my_scsi_cmd.interface_id    = 'S';
175         my_scsi_cmd.dxfer_direction = (mode == SCSI_IO_READ)?(SG_DXFER_FROM_DEV):(SG_DXFER_TO_DEV);
176         my_scsi_cmd.cmd_len         = cmdlen;
177         my_scsi_cmd.mx_sb_len       = 0;
178         my_scsi_cmd.dxfer_len       = len;
179         my_scsi_cmd.dxferp          = data;
180         my_scsi_cmd.cmdp            = cdb;
181         my_scsi_cmd.timeout         = ~0; /* where is MAX_UINT defined??? */
182
183 #ifdef DEBUG
184         printf("CMD(%d): %02x%02x%02x%02x%02x%02x %sdevice\n",cmdlen,cdb[0],cdb[1],cdb[2],cdb[3],cdb[4],cdb[5],
185                 (mode==SCSI_IO_READ)?("<-"):("->"));
186         printf("DATA   : len = %d\n",len);
187 #endif
188
189         if (ioctl(fd, SG_IO,&my_scsi_cmd) < 0) {
190                 perror("scsi_io");
191                 return -1;
192         }
193         
194         return my_scsi_cmd.status & STATUS_MASK;
195
196 #elif (defined _SCO_DS) && (defined SCSIUSERCMD)
197         struct scsicmd my_scsi_cmd;
198
199         memset(my_scsi_cmd.cdb, 0, SCSICMDLEN); /* ensure zero pad */
200         memcpy(my_scsi_cmd.cdb, cdb, cmdlen);
201         my_scsi_cmd.cdb_len = cmdlen;
202         my_scsi_cmd.data_len = len;
203         my_scsi_cmd.data_ptr = data;
204         my_scsi_cmd.is_write = mode == SCSI_IO_WRITE;
205         if (ioctl(fd,SCSIUSERCMD,&my_scsi_cmd) == -1) {
206                 perror("scsi_io: SCSIUSERCMD");
207                 return -1;
208         }
209         if (my_scsi_cmd.host_sts != 0 || my_scsi_cmd.target_sts != 0) {
210                 fprintf(stderr, "scsi_io: scsi status: host=%x; target=%x\n",
211                 (unsigned)my_scsi_cmd.host_sts,(unsigned)my_scsi_cmd.target_sts);
212                 return -1;
213         }
214         return 0;
215 #elif defined sgi
216         struct dsreq my_scsi_cmd;
217
218         my_scsi_cmd.ds_cmdbuf = (char *)cdb;
219         my_scsi_cmd.ds_cmdlen = cmdlen;
220         my_scsi_cmd.ds_databuf = data;
221         my_scsi_cmd.ds_datalen = len;
222         switch (mode) {
223         case SCSI_IO_READ:
224           my_scsi_cmd.ds_flags = DSRQ_READ|DSRQ_SENSE;
225           break;
226         case SCSI_IO_WRITE:
227           my_scsi_cmd.ds_flags = DSRQ_WRITE|DSRQ_SENSE;
228           break;
229         } 
230         my_scsi_cmd.ds_time = 10000;
231         my_scsi_cmd.ds_link = 0;
232         my_scsi_cmd.ds_synch =0;
233         my_scsi_cmd.ds_ret =0;
234         if (ioctl(fd, DS_ENTER, &my_scsi_cmd) == -1) {
235                 perror("scsi_io");
236                 return -1;
237         }
238
239         if(my_scsi_cmd.ds_status) {
240                 errno = 0;
241                 fprintf(stderr,"scsi status=%x\n",  
242                         (unsigned short)my_scsi_cmd.ds_status);
243                 return -1;
244         }
245         
246         return 0;
247 #elif (defined OS_freebsd) && (__FreeBSD__ >= 2)
248 #define MSG_SIMPLE_Q_TAG 0x20 /* O/O */
249       union ccb *ccb;
250       int flags;
251       int r;
252       struct cam_device *cam_dev = (struct cam_device *) extra_data;
253
254
255       if (cam_dev==NULL || cam_dev->fd!=fd)
256       {
257                 fprintf(stderr,"invalid file descriptor\n");
258               return -1;
259       }
260       ccb = cam_getccb(cam_dev);
261
262       bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cmdlen);
263
264       if (mode == SCSI_IO_READ)
265               flags = CAM_DIR_IN;
266       else if (data && len)
267               flags = CAM_DIR_OUT;
268       else
269               flags = CAM_DIR_NONE;
270       cam_fill_csio(&ccb->csio,
271                     /* retry */ 1,
272                     /* cbfcnp */ NULL,
273                     flags,
274                     /* tag_action */ MSG_SIMPLE_Q_TAG,
275                     /*data_ptr*/ len ? data : 0,
276                     /*data_len */ data ? len : 0,
277                     96,
278                     cmdlen,
279                     5000);
280                     
281       if (cam_send_ccb(cam_dev, ccb) < 0 ||
282           (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
283           return -1;
284       }
285       return 0;
286 #elif defined(OS_netbsd) || defined(OS_netbsdelf)
287         struct scsireq sc;
288
289         memset(&sc, 0, sizeof(sc));
290         memcpy(sc.cmd, cdb, cmdlen);
291         sc.cmdlen = cmdlen;
292         sc.databuf = data;
293         sc.datalen = len;
294         sc.senselen = 0;
295         sc.timeout = 10000;
296         switch (mode) {
297         case SCSI_IO_READ:
298           sc.flags = SCCMD_READ;
299           break;
300         case SCSI_IO_WRITE:
301           sc.flags = SCCMD_WRITE;
302           break;
303         }
304
305         if (ioctl(fd, SCIOCCOMMAND, &sc) == -1) {
306                 perror("SCIOCCOMMAND ioctl");
307                 return -1;
308         }
309
310         if (sc.retsts) {
311                 errno = EIO;
312                 fprintf(stderr, "SCSI command failed, retsts %d\n", 
313 sc.retsts);
314                 return -1;
315         }
316
317         return 0;
318 #else
319       fprintf(stderr, "scsi_io not implemented\n");
320       return -1;
321 #endif
322 }