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 #include <linux/param.h>
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.
26 #warning "HZ is not defined, mtx might not work correctly!"
27 #define HZ 100 /* Jiffys for SG_SET_TIMEOUT */
30 /* These are copied out of BRU 16.1, with all the boolean masks changed
33 #define S_NO_SENSE(s) ((s)->SenseKey == 0x0)
34 #define S_RECOVERED_ERROR(s) ((s)->SenseKey == 0x1)
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)
43 #define DEFAULT_TIMEOUT 3*60 /* 3 minutes here */
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.
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)
56 #define STILL_A_VALID_READ(s) (HIT_FILEMARK(s) || SHORT_READ(s) || HIT_EOD(s) || HIT_EOP(s) || HIT_EOM(s))
58 #define SG_SCSI_DEFAULT_TIMEOUT (HZ*60*5) /* 5 minutes? */
61 static int sg_timeout;
63 DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
65 int timeout = SG_SCSI_DEFAULT_TIMEOUT;
69 int DeviceFD = open(DeviceName, O_RDWR);
72 FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
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))
79 FatalError("%s is not an sg device, or old sg driver\n", DeviceName);
83 if (ioctl(DeviceFD, SG_SET_TIMEOUT, &timeout))
85 FatalError("failed to set sg timeout - %m\n");
87 pack_id = 1; /* used for SG v3 interface if possible. */
88 return (DEVICE_TYPE) DeviceFD;
91 void SCSI_Set_Timeout(int secs)
93 sg_timeout = secs * HZ;
96 void SCSI_Default_Timeout(void)
98 sg_timeout = SG_SCSI_DEFAULT_TIMEOUT;
101 void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
103 if (close(DeviceFD) < 0)
104 FatalError("cannot close SCSI device '%s' - %m\n", DeviceName);
108 /* Added by Eric Green <eric@estinc.com> to deal with burping
109 * Seagate autoloader (hopefully!).
111 /* Get the SCSI ID and LUN... */
112 scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd)
123 status = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun);
126 return NULL; /* sorry! */
129 retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
130 retval->id = idlun.word1 & 0xff;
131 retval->lun = idlun.word1 >> 8 & 0xff;
134 fprintf(stderr, "SCSI:ID=%d LUN=%d\n", retval->id, retval->lun);
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.
147 #include "sg_err.h" /* error stuff. */
148 #include "sg_err.c" /* some of Doug Gilbert's routines */
150 /* Use the new SG_IO structure */
151 int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
152 Direction_T Direction,
156 int DataBufferLength,
157 RequestSense_T *RequestSense)
162 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
163 memset(RequestSense, 0, sizeof(RequestSense_T));
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 */
175 if (Direction==Input)
177 /* fprintf(stderr,"direction=input\n"); */
178 io_hdr.dxfer_direction=SG_DXFER_FROM_DEV;
182 /* fprintf(stderr,"direction=output\n"); */
183 io_hdr.dxfer_direction=SG_DXFER_TO_DEV;
187 if ((status = ioctl(DeviceFD, SG_IO , &io_hdr)) || io_hdr.masked_status)
189 /* fprintf(stderr, "smt_scsi_cmd: Rval=%d Status=%d, errno=%d [%s]\n",status, io_hdr.masked_status,
193 switch (sg_err_category3(&io_hdr))
195 case SG_ERR_CAT_CLEAN:
196 case SG_ERR_CAT_RECOVERED:
199 case SG_ERR_CAT_MEDIA_CHANGED:
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 ); */
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 ); */
214 SCSI_Default_Timeout(); /* reset back to default timeout, sigh. */
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....
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.
234 #ifndef OLD_EXECUTE_COMMAND_STUFF
236 static void slow_memcopy(unsigned char *src, unsigned char *dest, int numbytes)
245 int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
246 Direction_T Direction,
250 int DataBufferLength,
251 RequestSense_T *RequestSense)
253 unsigned char *Command=NULL; /* the command data struct sent to them... */
254 unsigned char *ResultBuf=NULL; /* the data we read in return... */
256 unsigned char *src; /* for copying stuff, sigh. */
257 unsigned char *dest; /* for copy stuff, again, sigh. */
259 int write_length = sizeof(struct sg_header)+CDB_Length;
260 int i; /* a random index... */
261 int result; /* the result of the write... */
263 struct sg_header *Header; /* we actually point this into Command... */
264 struct sg_header *ResultHeader; /* we point this into ResultBuf... */
266 /* First, see if we need to set our SCSI timeout to something different */
267 if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT)
269 /* if not default, set it: */
271 fprintf(stderr,"Setting timeout to %d\n", sg_timeout);
274 if(ioctl(DeviceFD, SG_SET_TIMEOUT, &sg_timeout))
276 FatalError("failed to set sg timeout - %m\n");
280 if (Direction == Output)
282 /* if we're writing, our length is longer... */
283 write_length += DataBufferLength;
286 /* allocate some memory... enough for the command plus the header +
287 * any other data that we may need here...
290 Command = (unsigned char *)xmalloc(write_length);
291 Header = (struct sg_header *) Command; /* make it point to start of buf */
293 dest = Command; /* now to copy the CDB... from start of buffer,*/
294 dest += sizeof(struct sg_header); /* increment it past the header. */
296 slow_memcopy((char *)CDB, dest, CDB_Length);
298 /* if we are writing additional data, tack it on here! */
299 if (Direction == Output)
302 slow_memcopy(DataBuffer, dest, DataBufferLength); /* copy to end of command */
305 /* Now to fill in the Header struct: */
306 Header->reply_len=DataBufferLength+sizeof(struct sg_header);
308 fprintf(stderr,"sg:reply_len(sent)=%d\n",Header->reply_len);
310 Header->twelve_byte = CDB_Length == 12;
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? */
317 /* Now to do the write... */
318 result = write(DeviceFD,Command,write_length);
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.
324 if (result < 0 || result != write_length || Header->result || Header->sense_buffer[0])
327 fprintf(stderr,"scsi:result=%d Header->result=%d Header->sense_buffer[0]=%d\n",
328 result,Header->result,Header->sense_buffer[0]);
330 /* we don't have any real sense data, sigh :-(. */
331 if (Header->sense_buffer[0])
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));
339 dest=(unsigned char *)RequestSense;
340 *dest=(unsigned char)Header->result; /* may chop, sigh... */
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.
349 if (!STILL_A_VALID_READ(RequestSense))
351 free(Command); /* zap memory leak, sigh */
352 /* okay, find us a non-zero value to return :-(. */
357 else if (Header->result)
359 return Header->result;
363 return -1; /* sigh */
373 result=0; /* we're okay! */
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);
381 ResultHeader=(struct sg_header *)ResultBuf;
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! */
392 fprintf(stderr,"sg:Reading %d bytes from DeviceFD\n",Header->reply_len);
395 result=read(DeviceFD,ResultBuf,Header->reply_len);
397 fprintf(stderr,"sg:result=%d ResultHeader->result=%d\n",
398 result,ResultHeader->result);
401 /* New: added check to see if the result block is still all zeros! */
403 result != Header->reply_len ||
404 ResultHeader->result ||
405 ResultHeader->sense_buffer[0])
409 "scsi: result=%d Header->reply_len=%d ResultHeader->result=%d ResultHeader->sense_buffer[0]=%d\n",
412 ResultHeader->result,
413 ResultHeader->sense_buffer[0]);
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.
423 if (!STILL_A_VALID_READ(RequestSense))
431 else if (ResultHeader->result)
434 return ResultHeader->result;
439 return -1; /* sigh! */
444 result=-1; /* if it was a valid read, still have -1 result. */
452 /* See if we need to reset our SCSI timeout */
453 if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT)
455 sg_timeout = SG_SCSI_DEFAULT_TIMEOUT; /* reset it back to default */
458 fprintf(stderr,"Setting timeout to %d\n", sg_timeout);
461 /* if not default, set it: */
462 if (ioctl(DeviceFD, SG_SET_TIMEOUT, &sg_timeout))
464 FatalError("failed to set sg timeout - %m\n");
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)
473 fprintf(stderr,"Header->reply_len=%d,ResultHeader->reply_len=%d\n",
474 Header->reply_len,ResultHeader->reply_len);
476 src=ResultBuf+sizeof(struct sg_header);
478 for (i = 0; i < ResultHeader->reply_len; i++)
480 if (i >= DataBufferLength)
487 free(Command); /* clean up memory leak... */
489 return result; /* good stuff ! */
493 #endif /* #ifdef SG_IO */