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