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>
5 $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
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.
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
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.
24 #warning "HZ is not defined, mtx might not work correctly!"
25 #define HZ 100 /* Jiffys for SG_SET_TIMEOUT */
28 /* These are copied out of BRU 16.1, with all the boolean masks changed
31 #define S_NO_SENSE(s) ((s)->SenseKey == 0x0)
32 #define S_RECOVERED_ERROR(s) ((s)->SenseKey == 0x1)
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)
41 #define DEFAULT_TIMEOUT 3*60 /* 3 minutes here */
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.
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)
54 #define STILL_A_VALID_READ(s) (HIT_FILEMARK(s) || SHORT_READ(s) || HIT_EOD(s) || HIT_EOP(s) || HIT_EOM(s))
56 #define SG_SCSI_DEFAULT_TIMEOUT (HZ*60*5) /* 5 minutes? */
59 static int sg_timeout;
61 DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
63 int timeout = SG_SCSI_DEFAULT_TIMEOUT;
67 int DeviceFD = open(DeviceName, O_RDWR);
70 FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
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))
77 FatalError("%s is not an sg device, or old sg driver\n", DeviceName);
81 if (ioctl(DeviceFD, SG_SET_TIMEOUT, &timeout))
83 FatalError("failed to set sg timeout - %m\n");
85 pack_id = 1; /* used for SG v3 interface if possible. */
86 return (DEVICE_TYPE) DeviceFD;
89 void SCSI_Set_Timeout(int secs)
91 sg_timeout = secs * HZ;
94 void SCSI_Default_Timeout(void)
96 sg_timeout = SG_SCSI_DEFAULT_TIMEOUT;
99 void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
101 if (close(DeviceFD) < 0)
102 FatalError("cannot close SCSI device '%s' - %m\n", DeviceName);
106 /* Added by Eric Green <eric@estinc.com> to deal with burping
107 * Seagate autoloader (hopefully!).
109 /* Get the SCSI ID and LUN... */
110 scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd)
121 status = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun);
124 return NULL; /* sorry! */
127 retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
128 retval->id = idlun.word1 & 0xff;
129 retval->lun = idlun.word1 >> 8 & 0xff;
132 fprintf(stderr, "SCSI:ID=%d LUN=%d\n", retval->id, retval->lun);
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.
145 #include "sg_err.h" /* error stuff. */
146 #include "sg_err.c" /* some of Doug Gilbert's routines */
148 /* Use the new SG_IO structure */
149 int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
150 Direction_T Direction,
154 int DataBufferLength,
155 RequestSense_T *RequestSense)
160 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
161 memset(RequestSense, 0, sizeof(RequestSense_T));
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 */
173 if (Direction==Input)
175 /* fprintf(stderr,"direction=input\n"); */
176 io_hdr.dxfer_direction=SG_DXFER_FROM_DEV;
180 /* fprintf(stderr,"direction=output\n"); */
181 io_hdr.dxfer_direction=SG_DXFER_TO_DEV;
185 if ((status = ioctl(DeviceFD, SG_IO , &io_hdr)) || io_hdr.masked_status)
187 /* fprintf(stderr, "smt_scsi_cmd: Rval=%d Status=%d, errno=%d [%s]\n",status, io_hdr.masked_status,
191 switch (sg_err_category3(&io_hdr))
193 case SG_ERR_CAT_CLEAN:
194 case SG_ERR_CAT_RECOVERED:
197 case SG_ERR_CAT_MEDIA_CHANGED:
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 ); */
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 ); */
212 SCSI_Default_Timeout(); /* reset back to default timeout, sigh. */
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....
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.
232 #ifndef OLD_EXECUTE_COMMAND_STUFF
234 static void slow_memcopy(unsigned char *src, unsigned char *dest, int numbytes)
243 int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
244 Direction_T Direction,
248 int DataBufferLength,
249 RequestSense_T *RequestSense)
251 unsigned char *Command=NULL; /* the command data struct sent to them... */
252 unsigned char *ResultBuf=NULL; /* the data we read in return... */
254 unsigned char *src; /* for copying stuff, sigh. */
255 unsigned char *dest; /* for copy stuff, again, sigh. */
257 int write_length = sizeof(struct sg_header)+CDB_Length;
258 int i; /* a random index... */
259 int result; /* the result of the write... */
261 struct sg_header *Header; /* we actually point this into Command... */
262 struct sg_header *ResultHeader; /* we point this into ResultBuf... */
264 /* First, see if we need to set our SCSI timeout to something different */
265 if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT)
267 /* if not default, set it: */
269 fprintf(stderr,"Setting timeout to %d\n", sg_timeout);
272 if(ioctl(DeviceFD, SG_SET_TIMEOUT, &sg_timeout))
274 FatalError("failed to set sg timeout - %m\n");
278 if (Direction == Output)
280 /* if we're writing, our length is longer... */
281 write_length += DataBufferLength;
284 /* allocate some memory... enough for the command plus the header +
285 * any other data that we may need here...
288 Command = (unsigned char *)xmalloc(write_length);
289 Header = (struct sg_header *) Command; /* make it point to start of buf */
291 dest = Command; /* now to copy the CDB... from start of buffer,*/
292 dest += sizeof(struct sg_header); /* increment it past the header. */
294 slow_memcopy((char *)CDB, dest, CDB_Length);
296 /* if we are writing additional data, tack it on here! */
297 if (Direction == Output)
300 slow_memcopy(DataBuffer, dest, DataBufferLength); /* copy to end of command */
303 /* Now to fill in the Header struct: */
304 Header->reply_len=DataBufferLength+sizeof(struct sg_header);
306 fprintf(stderr,"sg:reply_len(sent)=%d\n",Header->reply_len);
308 Header->twelve_byte = CDB_Length == 12;
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? */
315 /* Now to do the write... */
316 result = write(DeviceFD,Command,write_length);
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.
322 if (result < 0 || result != write_length || Header->result || Header->sense_buffer[0])
325 fprintf(stderr,"scsi:result=%d Header->result=%d Header->sense_buffer[0]=%d\n",
326 result,Header->result,Header->sense_buffer[0]);
328 /* we don't have any real sense data, sigh :-(. */
329 if (Header->sense_buffer[0])
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));
337 dest=(unsigned char *)RequestSense;
338 *dest=(unsigned char)Header->result; /* may chop, sigh... */
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.
347 if (!STILL_A_VALID_READ(RequestSense))
349 free(Command); /* zap memory leak, sigh */
350 /* okay, find us a non-zero value to return :-(. */
355 else if (Header->result)
357 return Header->result;
361 return -1; /* sigh */
371 result=0; /* we're okay! */
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);
379 ResultHeader=(struct sg_header *)ResultBuf;
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! */
390 fprintf(stderr,"sg:Reading %d bytes from DeviceFD\n",Header->reply_len);
393 result=read(DeviceFD,ResultBuf,Header->reply_len);
395 fprintf(stderr,"sg:result=%d ResultHeader->result=%d\n",
396 result,ResultHeader->result);
399 /* New: added check to see if the result block is still all zeros! */
401 result != Header->reply_len ||
402 ResultHeader->result ||
403 ResultHeader->sense_buffer[0])
407 "scsi: result=%d Header->reply_len=%d ResultHeader->result=%d ResultHeader->sense_buffer[0]=%d\n",
410 ResultHeader->result,
411 ResultHeader->sense_buffer[0]);
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.
421 if (!STILL_A_VALID_READ(RequestSense))
429 else if (ResultHeader->result)
432 return ResultHeader->result;
437 return -1; /* sigh! */
442 result=-1; /* if it was a valid read, still have -1 result. */
450 /* See if we need to reset our SCSI timeout */
451 if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT)
453 sg_timeout = SG_SCSI_DEFAULT_TIMEOUT; /* reset it back to default */
456 fprintf(stderr,"Setting timeout to %d\n", sg_timeout);
459 /* if not default, set it: */
460 if (ioctl(DeviceFD, SG_SET_TIMEOUT, &sg_timeout))
462 FatalError("failed to set sg timeout - %m\n");
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)
471 fprintf(stderr,"Header->reply_len=%d,ResultHeader->reply_len=%d\n",
472 Header->reply_len,ResultHeader->reply_len);
474 src=ResultBuf+sizeof(struct sg_header);
476 for (i = 0; i < ResultHeader->reply_len; i++)
478 if (i >= DataBufferLength)
485 free(Command); /* clean up memory leak... */
487 return result; /* good stuff ! */
491 #endif /* #ifdef SG_IO */