1 /* Copyright 1997, 1998 Leonard Zubkoff <lnz@dandelion.com>
2 Changes in Feb 2000 Eric Green <eric@badtux.org>
4 $Date: 2007-03-24 21:17:10 -0700 (Sat, 24 Mar 2007) $
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.
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
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.
23 #warning "HZ is not defined, mtx might not work correctly!"
24 #define HZ 100 /* Jiffys for SG_SET_TIMEOUT */
27 /* These are copied out of BRU 16.1, with all the boolean masks changed
30 #define S_NO_SENSE(s) ((s)->SenseKey == 0x0)
31 #define S_RECOVERED_ERROR(s) ((s)->SenseKey == 0x1)
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)
40 #define DEFAULT_TIMEOUT 3*60 /* 3 minutes here */
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.
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)
53 #define STILL_A_VALID_READ(s) (HIT_FILEMARK(s) || SHORT_READ(s) || HIT_EOD(s) || HIT_EOP(s) || HIT_EOM(s))
55 #define SG_SCSI_DEFAULT_TIMEOUT (HZ*60*5) /* 5 minutes? */
58 static int sg_timeout;
60 DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
62 int timeout = SG_SCSI_DEFAULT_TIMEOUT;
66 int DeviceFD = open(DeviceName, O_RDWR);
69 FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
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))
76 FatalError("%s is not an sg device, or old sg driver\n", DeviceName);
80 if (ioctl(DeviceFD, SG_SET_TIMEOUT, &timeout))
82 FatalError("failed to set sg timeout - %m\n");
84 pack_id = 1; /* used for SG v3 interface if possible. */
85 return (DEVICE_TYPE) DeviceFD;
88 void SCSI_Set_Timeout(int secs)
90 sg_timeout = secs * HZ;
93 void SCSI_Default_Timeout(void)
95 sg_timeout = SG_SCSI_DEFAULT_TIMEOUT;
98 void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
100 if (close(DeviceFD) < 0)
101 FatalError("cannot close SCSI device '%s' - %m\n", DeviceName);
105 /* Added by Eric Green <eric@estinc.com> to deal with burping
106 * Seagate autoloader (hopefully!).
108 /* Get the SCSI ID and LUN... */
109 scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd)
120 status = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun);
123 return NULL; /* sorry! */
126 retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
127 retval->id = idlun.word1 & 0xff;
128 retval->lun = idlun.word1 >> 8 & 0xff;
131 fprintf(stderr, "SCSI:ID=%d LUN=%d\n", retval->id, retval->lun);
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.
144 #include "sg_err.h" /* error stuff. */
145 #include "sg_err.c" /* some of Doug Gilbert's routines */
147 /* Use the new SG_IO structure */
148 int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
149 Direction_T Direction,
153 int DataBufferLength,
154 RequestSense_T *RequestSense)
159 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
160 memset(RequestSense, 0, sizeof(RequestSense_T));
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 */
172 if (Direction==Input)
174 /* fprintf(stderr,"direction=input\n"); */
175 io_hdr.dxfer_direction=SG_DXFER_FROM_DEV;
179 /* fprintf(stderr,"direction=output\n"); */
180 io_hdr.dxfer_direction=SG_DXFER_TO_DEV;
184 if ((status = ioctl(DeviceFD, SG_IO , &io_hdr)) || io_hdr.masked_status)
186 /* fprintf(stderr, "smt_scsi_cmd: Rval=%d Status=%d, errno=%d [%s]\n",status, io_hdr.masked_status,
190 switch (sg_err_category3(&io_hdr))
192 case SG_ERR_CAT_CLEAN:
193 case SG_ERR_CAT_RECOVERED:
196 case SG_ERR_CAT_MEDIA_CHANGED:
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 ); */
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 ); */
211 SCSI_Default_Timeout(); /* reset back to default timeout, sigh. */
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....
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.
231 #ifndef OLD_EXECUTE_COMMAND_STUFF
233 static void slow_memcopy(unsigned char *src, unsigned char *dest, int numbytes)
242 int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
243 Direction_T Direction,
247 int DataBufferLength,
248 RequestSense_T *RequestSense)
250 unsigned char *Command=NULL; /* the command data struct sent to them... */
251 unsigned char *ResultBuf=NULL; /* the data we read in return... */
253 unsigned char *src; /* for copying stuff, sigh. */
254 unsigned char *dest; /* for copy stuff, again, sigh. */
256 int write_length = sizeof(struct sg_header)+CDB_Length;
257 int i; /* a random index... */
258 int result; /* the result of the write... */
260 struct sg_header *Header; /* we actually point this into Command... */
261 struct sg_header *ResultHeader; /* we point this into ResultBuf... */
263 /* First, see if we need to set our SCSI timeout to something different */
264 if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT)
266 /* if not default, set it: */
268 fprintf(stderr,"Setting timeout to %d\n", sg_timeout);
271 if(ioctl(DeviceFD, SG_SET_TIMEOUT, &sg_timeout))
273 FatalError("failed to set sg timeout - %m\n");
277 if (Direction == Output)
279 /* if we're writing, our length is longer... */
280 write_length += DataBufferLength;
283 /* allocate some memory... enough for the command plus the header +
284 * any other data that we may need here...
287 Command = (unsigned char *)xmalloc(write_length);
288 Header = (struct sg_header *) Command; /* make it point to start of buf */
290 dest = Command; /* now to copy the CDB... from start of buffer,*/
291 dest += sizeof(struct sg_header); /* increment it past the header. */
293 slow_memcopy((char *)CDB, dest, CDB_Length);
295 /* if we are writing additional data, tack it on here! */
296 if (Direction == Output)
299 slow_memcopy(DataBuffer, dest, DataBufferLength); /* copy to end of command */
302 /* Now to fill in the Header struct: */
303 Header->reply_len=DataBufferLength+sizeof(struct sg_header);
305 fprintf(stderr,"sg:reply_len(sent)=%d\n",Header->reply_len);
307 Header->twelve_byte = CDB_Length == 12;
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? */
314 /* Now to do the write... */
315 result = write(DeviceFD,Command,write_length);
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.
321 if (result < 0 || result != write_length || Header->result || Header->sense_buffer[0])
324 fprintf(stderr,"scsi:result=%d Header->result=%d Header->sense_buffer[0]=%d\n",
325 result,Header->result,Header->sense_buffer[0]);
327 /* we don't have any real sense data, sigh :-(. */
328 if (Header->sense_buffer[0])
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));
336 dest=(unsigned char *)RequestSense;
337 *dest=(unsigned char)Header->result; /* may chop, sigh... */
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.
346 if (!STILL_A_VALID_READ(RequestSense))
348 free(Command); /* zap memory leak, sigh */
349 /* okay, find us a non-zero value to return :-(. */
354 else if (Header->result)
356 return Header->result;
360 return -1; /* sigh */
370 result=0; /* we're okay! */
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);
378 ResultHeader=(struct sg_header *)ResultBuf;
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! */
389 fprintf(stderr,"sg:Reading %d bytes from DeviceFD\n",Header->reply_len);
392 result=read(DeviceFD,ResultBuf,Header->reply_len);
394 fprintf(stderr,"sg:result=%d ResultHeader->result=%d\n",
395 result,ResultHeader->result);
398 /* New: added check to see if the result block is still all zeros! */
400 result != Header->reply_len ||
401 ResultHeader->result ||
402 ResultHeader->sense_buffer[0])
406 "scsi: result=%d Header->reply_len=%d ResultHeader->result=%d ResultHeader->sense_buffer[0]=%d\n",
409 ResultHeader->result,
410 ResultHeader->sense_buffer[0]);
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.
420 if (!STILL_A_VALID_READ(RequestSense))
428 else if (ResultHeader->result)
431 return ResultHeader->result;
436 return -1; /* sigh! */
441 result=-1; /* if it was a valid read, still have -1 result. */
449 /* See if we need to reset our SCSI timeout */
450 if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT)
452 sg_timeout = SG_SCSI_DEFAULT_TIMEOUT; /* reset it back to default */
455 fprintf(stderr,"Setting timeout to %d\n", sg_timeout);
458 /* if not default, set it: */
459 if (ioctl(DeviceFD, SG_SET_TIMEOUT, &sg_timeout))
461 FatalError("failed to set sg timeout - %m\n");
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)
470 fprintf(stderr,"Header->reply_len=%d,ResultHeader->reply_len=%d\n",
471 Header->reply_len,ResultHeader->reply_len);
473 src=ResultBuf+sizeof(struct sg_header);
475 for (i = 0; i < ResultHeader->reply_len; i++)
477 if (i >= DataBufferLength)
484 free(Command); /* clean up memory leak... */
486 return result; /* good stuff ! */
490 #endif /* #ifdef SG_IO */