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