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