fix lintian issues
[debian/mtx] / scsi_linux.c
1 /* Copyright 1997, 1998 Leonard Zubkoff <lnz@dandelion.com>
2    Changes in Feb 2000 Eric Green <eric@badtux.org>
3    Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
4
5 $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
6 $Revision: 193 $
7
8   This program is free software; you may redistribute and/or modify it under
9   the terms of the GNU General Public License Version 2 as published by the
10   Free Software Foundation.
11
12   This program is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
14   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15   for complete details.
16
17 */
18
19 /* this is the SCSI commands for Linux. Note that <eric@badtux.org> changed 
20  * it from using SCSI_IOCTL_SEND_COMMAND to using the SCSI generic interface.
21  */
22
23 #ifndef HZ
24 #warning "HZ is not defined, mtx might not work correctly!"
25 #define HZ 100    /* Jiffys for SG_SET_TIMEOUT */
26 #endif
27
28 /* These are copied out of BRU 16.1, with all the boolean masks changed
29  * to our bitmasks.
30 */
31 #define S_NO_SENSE(s) ((s)->SenseKey == 0x0)
32 #define S_RECOVERED_ERROR(s) ((s)->SenseKey == 0x1)
33
34 #define S_NOT_READY(s) ((s)->SenseKey == 0x2)
35 #define S_MEDIUM_ERROR(s) ((s)->SenseKey == 0x3)
36 #define S_HARDWARE_ERROR(s) ((s)->SenseKey == 0x4)
37 #define S_UNIT_ATTENTION(s) ((s)->SenseKey == 0x6)
38 #define S_BLANK_CHECK(s) ((s)->SenseKey == 0x8)
39 #define S_VOLUME_OVERFLOW(s) ((s)->SenseKey == 0xd)
40
41 #define DEFAULT_TIMEOUT 3*60  /* 3 minutes here */
42
43 /* Sigh, the T-10 SSC spec says all of the following is needed to
44  * detect a short read while in variable block mode, and that even
45  * though we got a BLANK_CHECK or MEDIUM_ERROR, it's still a valid read.
46  */
47
48 #define HIT_FILEMARK(s) (S_NO_SENSE((s)) && (s)->Filemark && (s)->Valid)
49 #define SHORT_READ(s) (S_NO_SENSE((s)) && (s)->ILI && (s)->Valid &&  (s)->AdditionalSenseCode==0  && (s)->AdditionalSenseCodeQualifier==0)
50 #define HIT_EOD(s) (S_BLANK_CHECK((s)) && (s)->Valid)
51 #define HIT_EOP(s) (S_MEDIUM_ERROR((s)) && (s)->EOM && (s)->Valid)
52 #define HIT_EOM(s) ((s)->EOM && (s)->Valid)
53
54 #define STILL_A_VALID_READ(s) (HIT_FILEMARK(s) || SHORT_READ(s) || HIT_EOD(s) || HIT_EOP(s) || HIT_EOM(s))
55
56 #define SG_SCSI_DEFAULT_TIMEOUT (HZ*60*5)  /* 5 minutes? */
57
58 static int pack_id;
59 static int sg_timeout;
60
61 DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
62 {
63         int timeout = SG_SCSI_DEFAULT_TIMEOUT;
64 #ifdef SG_IO
65         int k; /* version */
66 #endif
67         int DeviceFD = open(DeviceName, O_RDWR);
68
69         if (DeviceFD < 0)
70                 FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
71
72
73 #ifdef SG_IO
74         /* It is prudent to check we have a sg device by trying an ioctl */
75         if ((ioctl(DeviceFD, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000))
76         {
77                 FatalError("%s is not an sg device, or old sg driver\n", DeviceName);
78         }
79 #endif
80
81         if (ioctl(DeviceFD, SG_SET_TIMEOUT, &timeout))
82         {
83                 FatalError("failed to set sg timeout - %m\n");
84         }
85         pack_id = 1;    /* used for SG v3 interface if possible. */
86         return (DEVICE_TYPE) DeviceFD;
87 }
88
89 void SCSI_Set_Timeout(int secs)
90 {
91         sg_timeout = secs * HZ;
92 }
93  
94 void SCSI_Default_Timeout(void)
95 {
96         sg_timeout = SG_SCSI_DEFAULT_TIMEOUT;
97 }
98
99 void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
100 {
101         if (close(DeviceFD) < 0)
102                 FatalError("cannot close SCSI device '%s' - %m\n", DeviceName);
103 }
104
105
106 /* Added by Eric Green <eric@estinc.com> to deal with burping
107  * Seagate autoloader (hopefully!). 
108  */
109 /* Get the SCSI ID and LUN... */
110 scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd)
111 {
112         int status;
113         scsi_id_t *retval;
114
115         struct my_scsi_idlun
116         {
117                 int word1;
118                 int word2;
119         } idlun;
120
121         status = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun);
122         if (status)
123         {
124                 return NULL; /* sorry! */
125         }
126
127         retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
128         retval->id = idlun.word1 & 0xff;
129         retval->lun = idlun.word1 >> 8 & 0xff;
130
131 #ifdef DEBUG
132         fprintf(stderr, "SCSI:ID=%d LUN=%d\n", retval->id, retval->lun);
133 #endif
134
135         return retval;
136 }
137
138
139 /* Changed January 2001 by Eric Green <eric@badtux.org> to 
140  * use the Linux version 2.4 SCSI Generic facility if available.
141  * Liberally cribbed code from Doug Gilbert's sg3 utils. 
142  */
143
144 #ifdef SG_IO
145 #include "sg_err.h"  /* error stuff. */
146 #include "sg_err.c"  /* some of Doug Gilbert's routines */
147
148 /* Use the new SG_IO structure */
149 int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
150                                                 Direction_T Direction,
151                                                 CDB_T *CDB,
152                                                 int CDB_Length,
153                                                 void *DataBuffer,
154                                                 int DataBufferLength,
155                                                 RequestSense_T *RequestSense)
156 {
157         unsigned int status;
158         sg_io_hdr_t io_hdr;
159
160         memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
161         memset(RequestSense, 0, sizeof(RequestSense_T));
162
163         /* Fill in the common stuff... */
164         io_hdr.interface_id = 'S';
165         io_hdr.cmd_len = CDB_Length;
166         io_hdr.mx_sb_len = sizeof(RequestSense_T);
167         io_hdr.dxfer_len = DataBufferLength;
168         io_hdr.cmdp = (unsigned char *) CDB;
169         io_hdr.sbp = (unsigned char *) RequestSense;
170         io_hdr.dxferp = DataBuffer;
171         io_hdr.timeout = sg_timeout * 10; /* Convert from Jiffys to milliseconds */
172
173         if (Direction==Input)
174         {
175                 /* fprintf(stderr,"direction=input\n"); */
176                 io_hdr.dxfer_direction=SG_DXFER_FROM_DEV;
177         }
178         else
179         {
180                 /* fprintf(stderr,"direction=output\n"); */
181                 io_hdr.dxfer_direction=SG_DXFER_TO_DEV;
182         }
183
184         /* Now do it:  */
185         if ((status = ioctl(DeviceFD, SG_IO , &io_hdr)) || io_hdr.masked_status)
186         {
187                 /* fprintf(stderr, "smt_scsi_cmd: Rval=%d Status=%d, errno=%d [%s]\n",status, io_hdr.masked_status,
188                 errno, 
189                 strerror(errno)); */
190
191                 switch (sg_err_category3(&io_hdr))
192                 {
193                 case SG_ERR_CAT_CLEAN:
194                 case SG_ERR_CAT_RECOVERED:
195                         break;
196
197                 case SG_ERR_CAT_MEDIA_CHANGED:
198                         return 2;
199
200                 default:
201                         return -1;
202                 }
203
204                 /*  fprintf(stderr,"host_status=%d driver_status=%d residual=%d writelen=%d\n",io_hdr.host_status,io_hdr.driver_status,io_hdr.resid,io_hdr.sb_len_wr ); */
205
206                 return -errno;
207         }
208
209         /* Now check the returned statuses: */
210         /* fprintf(stderr,"host_status=%d driver_status=%d residual=%d writelen=%d\n",io_hdr.host_status,io_hdr.driver_status,io_hdr.resid,io_hdr.sb_len_wr ); */
211
212         SCSI_Default_Timeout();  /* reset back to default timeout, sigh. */
213         return 0;
214 }
215
216 #else
217
218 /* Changed February 2000 by Eric Green <eric@estinc.com> to 
219  * use the SCSI generic interface rather than SCSI_IOCTL_SEND_COMMAND
220  * so that we can get more than PAGE_SIZE data....
221  *
222  * Note that the SCSI generic interface abuses READ and WRITE calls to serve
223  * the same purpose as IOCTL calls, i.e., for "writes", the contents of the
224  * buffer that you send as the argument to the write() call are actually
225  * altered to fill in result status and sense data (if needed). 
226  * Also note that this brain-dead interface does not have any sort of 
227  * provisions for expanding the sg_header struct in a backward-compatible
228  * manner. This sucks. But sucks less than SCSI_IOCTL_SEND_COMMAND, sigh.
229  */
230
231
232 #ifndef OLD_EXECUTE_COMMAND_STUFF
233
234 static void slow_memcopy(unsigned char *src, unsigned char *dest, int numbytes)
235 {
236         while (numbytes--)
237         {
238                 *dest++ = *src++;
239         }
240 }
241
242
243 int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
244                                                 Direction_T Direction,
245                                                 CDB_T *CDB,
246                                                 int CDB_Length,
247                                                 void *DataBuffer,
248                                                 int DataBufferLength,
249                                                 RequestSense_T *RequestSense)
250 {
251         unsigned char *Command=NULL;   /* the command data struct sent to them... */
252         unsigned char *ResultBuf=NULL; /* the data we read in return...         */
253
254         unsigned char *src;       /* for copying stuff, sigh. */
255         unsigned char *dest;      /* for copy stuff, again, sigh. */
256
257         int write_length = sizeof(struct sg_header)+CDB_Length;
258         int i;                  /* a random index...          */
259         int result;             /* the result of the write... */ 
260
261         struct sg_header *Header; /* we actually point this into Command... */
262         struct sg_header *ResultHeader; /* we point this into ResultBuf... */
263
264         /* First, see if we need to set our SCSI timeout to something different */
265         if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT)
266         {
267                 /* if not default, set it: */
268 #ifdef DEBUG_TIMEOUT
269                 fprintf(stderr,"Setting timeout to %d\n", sg_timeout);
270                 fflush(stderr);
271 #endif
272                 if(ioctl(DeviceFD, SG_SET_TIMEOUT, &sg_timeout))
273                 {
274                         FatalError("failed to set sg timeout - %m\n");
275                 }
276         }
277
278         if (Direction == Output)
279         {
280                 /* if we're writing, our length is longer... */
281                 write_length += DataBufferLength; 
282         }
283
284         /* allocate some memory... enough for the command plus the header +
285          *  any other data that we may need here...
286          */
287
288         Command = (unsigned char *)xmalloc(write_length);
289         Header = (struct sg_header *) Command;  /* make it point to start of buf */
290
291         dest = Command; /* now to copy the CDB... from start of buffer,*/
292         dest += sizeof(struct sg_header); /* increment it past the header. */
293
294         slow_memcopy((char *)CDB, dest, CDB_Length);
295
296         /* if we are writing additional data, tack it on here! */
297         if (Direction == Output)
298         {
299                 dest += CDB_Length;
300                 slow_memcopy(DataBuffer, dest, DataBufferLength); /* copy to end of command */
301         }
302
303         /* Now to fill in the Header struct: */
304         Header->reply_len=DataBufferLength+sizeof(struct sg_header);
305 #ifdef DEBUG
306         fprintf(stderr,"sg:reply_len(sent)=%d\n",Header->reply_len);
307 #endif
308         Header->twelve_byte = CDB_Length == 12; 
309         Header->result = 0;
310         Header->pack_len = write_length; /* # of bytes written... */
311         Header->pack_id = 0;             /* not used              */
312         Header->other_flags = 0;         /* not used.             */
313         Header->sense_buffer[0]=0;      /* used? */
314
315         /* Now to do the write... */
316         result = write(DeviceFD,Command,write_length);
317
318         /* Now to check the result :-(. */
319         /* Note that we don't have any request sense here. So we have no
320         * idea what's going on. 
321         */ 
322         if (result < 0 || result != write_length || Header->result || Header->sense_buffer[0])
323         {
324 #ifdef DEBUG_SCSI
325                 fprintf(stderr,"scsi:result=%d Header->result=%d Header->sense_buffer[0]=%d\n",
326                 result,Header->result,Header->sense_buffer[0]);
327 #endif  
328                 /* we don't have any real sense data, sigh :-(. */
329                 if (Header->sense_buffer[0])
330                 {
331                         /* well, I guess we DID have some! eep! copy the sense data! */
332                         slow_memcopy((char *)Header->sense_buffer,(char *)RequestSense,
333                                                  sizeof(Header->sense_buffer));
334                 }
335                 else
336                 {
337                         dest=(unsigned char *)RequestSense;
338                         *dest=(unsigned char)Header->result; /* may chop, sigh... */
339                 }
340
341                 /* okay, now, we may or may not need to find a non-zero value to return.
342                 * For tape drives, we may get a BLANK_CHECK or MEDIUM_ERROR and find
343                 * that it's *STILL* a good read! Use the STILL_A_VALID_READ macro
344                 * that calls all those macros I cribbed from Richard. 
345                 */
346
347                 if (!STILL_A_VALID_READ(RequestSense))
348                 {
349                         free(Command); /* zap memory leak, sigh */
350                         /* okay, find us a non-zero value to return :-(. */
351                         if (result)
352                         {
353                                 return result;
354                         }
355                         else if (Header->result)
356                         {
357                                 return Header->result;
358                         }
359                         else
360                         {
361                                 return -1;  /* sigh */
362                         }
363                 }
364                 else
365                 {
366                         result=-1;
367                 }
368         }
369         else
370         {
371                 result=0; /* we're okay! */
372         }
373
374         /* now to allocate the new block.... */
375         ResultBuf=(unsigned char *)xmalloc(Header->reply_len);
376         /* now to clear ResultBuf... */
377         slow_bzero(ResultBuf,Header->reply_len); 
378
379         ResultHeader=(struct sg_header *)ResultBuf;
380
381         /* copy the original Header... */
382         ResultHeader->result=0;
383         ResultHeader->pack_id=0;
384         ResultHeader->other_flags=0;
385         ResultHeader->reply_len=Header->reply_len;
386         ResultHeader->twelve_byte = CDB_Length == 12; 
387         ResultHeader->pack_len = write_length; /* # of bytes written... */
388         ResultHeader->sense_buffer[0]=0; /* whoops! Zero that! */
389 #ifdef DEBUG
390         fprintf(stderr,"sg:Reading %d bytes from DeviceFD\n",Header->reply_len);
391         fflush(stderr);
392 #endif
393         result=read(DeviceFD,ResultBuf,Header->reply_len);
394 #ifdef DEBUG
395         fprintf(stderr,"sg:result=%d ResultHeader->result=%d\n",
396         result,ResultHeader->result);
397         fflush(stderr);
398 #endif
399         /* New: added check to see if the result block is still all zeros! */
400         if (result < 0 ||
401                 result != Header->reply_len ||
402                 ResultHeader->result ||
403                 ResultHeader->sense_buffer[0])
404         {
405 #ifdef DEBUG
406                 fprintf(stderr,
407                 "scsi: result=%d Header->reply_len=%d ResultHeader->result=%d ResultHeader->sense_buffer[0]=%d\n",
408                 result,
409                 Header->reply_len,
410                 ResultHeader->result,
411                 ResultHeader->sense_buffer[0]);
412 #endif
413                 /* eep! copy the sense data! */
414                 slow_memcopy((char *)ResultHeader->sense_buffer,(char *)RequestSense,
415                 sizeof(ResultHeader->sense_buffer));
416                 /* sense data copied, now find us a non-zero value to return :-(. */
417                 /* NOTE: Some commands return sense data even though they validly
418                 * executed! We catch a few of those with the macro STILL_A_VALID_READ.
419                 */
420
421                 if (!STILL_A_VALID_READ(RequestSense))
422                 {
423                         free(Command);
424                         if (result)
425                         {
426                                 free(ResultBuf);
427                                 return result;
428                         }
429                         else if (ResultHeader->result)
430                         {
431                                 free(ResultBuf);
432                                 return ResultHeader->result;
433                         }
434                         else
435                         {
436                                 free(ResultBuf);
437                                 return -1; /* sigh! */
438                         } 
439                 }
440                 else
441                 {
442                         result=-1; /* if it was a valid read, still have -1 result. */
443                 }
444         }
445         else
446         {
447                 result=0;
448         }
449
450         /* See if we need to reset our SCSI timeout */
451         if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT)
452         {
453                 sg_timeout = SG_SCSI_DEFAULT_TIMEOUT; /* reset it back to default */
454
455 #ifdef DEBUG_TIMEOUT
456                 fprintf(stderr,"Setting timeout to %d\n", sg_timeout);
457                 fflush(stderr);
458 #endif
459                 /* if not default, set it: */
460                 if (ioctl(DeviceFD, SG_SET_TIMEOUT, &sg_timeout))
461                 {
462                         FatalError("failed to set sg timeout - %m\n");
463                 }
464         }
465
466         /* now for the crowning moment: copying any result into the DataBuffer! */
467         /* (but only if it were an input command and not an output command :-}  */
468         if (Direction == Input)
469         {
470 #ifdef DEBUG
471                 fprintf(stderr,"Header->reply_len=%d,ResultHeader->reply_len=%d\n",
472                 Header->reply_len,ResultHeader->reply_len);
473 #endif
474                 src=ResultBuf+sizeof(struct sg_header);
475                 dest=DataBuffer;
476                 for (i = 0; i < ResultHeader->reply_len; i++)
477                 {
478                         if (i >= DataBufferLength)
479                                 break;  /* eep! */
480                         *dest++ = *src++;
481                 }
482         }
483
484         /* and return! */
485         free(Command);    /* clean up memory leak... */
486         free(ResultBuf);
487         return result; /* good stuff ! */
488 }
489
490 #endif  
491 #endif   /* #ifdef  SG_IO    */