1 /* sane - Scanner Access Now Easy.
2    Copyright (C) 1996, 1997 David Mosberger-Tang
3    Copyright (C) 2003 Frank Zago
4    This file is part of the SANE package.
5 
6    This program is free software; you can redistribute it and/or
7    modify it under the terms of the GNU General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
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
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <https://www.gnu.org/licenses/>.
18 
19    As a special exception, the authors of SANE give permission for
20    additional uses of the libraries contained in this release of SANE.
21 
22    The exception is that, if you link a SANE library with other files
23    to produce an executable, this does not by itself cause the
24    resulting executable to be covered by the GNU General Public
25    License.  Your use of that executable is in no way restricted on
26    account of linking the SANE library code into it.
27 
28    This exception does not, however, invalidate any other reasons why
29    the executable file might be covered by the GNU General Public
30    License.
31 
32    If you submit changes to SANE to the maintainers to be included in
33    a subsequent release, you agree by submitting the changes that
34    those changes may be distributed with this exception intact.
35 
36    If you write modifications of your own for SANE, it is your choice
37    whether to permit this exception to apply to your modifications.
38    If you do not wish that, delete this exception notice.
39 
40    This file provides a generic SCSI interface.  */
41 
42 #ifdef _AIX
43 # include "../include/lalloca.h"	/* MUST come first for AIX! */
44 #endif
45 
46 #include "../include/sane/config.h"
47 #include "../include/lalloca.h"
48 #include "../include/lassert.h"
49 
50 #include <ctype.h>
51 #include <errno.h>
52 #include <fcntl.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 
57 #ifdef HAVE_SYS_IOCTL_H
58 #include <sys/ioctl.h>
59 #endif
60 #include <sys/param.h>
61 #include <sys/types.h>
62 
63 #if defined (HAVE_WINDOWS_H)
64 # include <windows.h>
65 #endif
66 
67 #define STUBBED_INTERFACE	0
68 #define LINUX_INTERFACE		1
69 #define BSD_INTERFACE		2
70 #define	HPUX_INTERFACE		3
71 #define OPENSTEP_INTERFACE	4
72 #define DECUNIX_INTERFACE	5
73 #define SCO_OS5_INTERFACE	6
74 #define IRIX_INTERFACE		7
75 #define SOLARIS_INTERFACE	8
76 #define SOLARIS_SG_INTERFACE	9
77 #define OS2_INTERFACE		10
78 #define AIX_GSC_INTERFACE	11
79 #define DOMAINOS_INTERFACE	12
80 #define FREEBSD_CAM_INTERFACE	13
81 #define SYSVR4_INTERFACE	14
82 #define SCO_UW71_INTERFACE	15
83 #define SOLARIS_USCSI_INTERFACE	16
84 #define MACOSX_INTERFACE	17
85 #define WIN32_INTERFACE		18
86 
87 #ifdef HAVE_RESMGR
88 # include <resmgr.h>
89 #endif
90 
91 #if defined (HAVE_SCSI_SG_H)
92 # define USE LINUX_INTERFACE
93 # include <scsi/sg.h>
94 #elif defined (HAVE__USR_SRC_LINUX_INCLUDE_SCSI_SG_H)
95 # define USE LINUX_INTERFACE
96 # include "/usr/src/linux/include/scsi/sg.h"
97 #elif defined (HAVE_SYS_SCSICMD_H)
98 # define USE SCSO_OS5_INTERFACE
99 # include <sys/scsi.h>
100 # include <sys/scsicmd.h>
101 #elif defined (HAVE_CAMLIB_H)
102 # define USE FREEBSD_CAM_INTERFACE
103 # include <stdio.h>		/* there is a bug in scsi_all.h */
104 # ifdef __DragonFly__
105 # include <bus/cam/cam.h>
106 # include <bus/cam/cam_ccb.h>
107 # include <bus/cam/scsi/scsi_message.h>
108 # include <bus/cam/scsi/scsi_pass.h>
109 # else
110 # include <cam/cam.h>
111 # include <cam/cam_ccb.h>
112 # include <cam/scsi/scsi_message.h>
113 # include <cam/scsi/scsi_pass.h>
114 # endif
115 # include <camlib.h>
116 #elif defined (HAVE_SYS_SCSIIO_H)
117 # define USE BSD_INTERFACE
118 # include <sys/scsiio.h>
119 # ifdef HAVE_SCSI_H
120 #  include <scsi.h>
121 # endif
122 #elif defined (HAVE_BSD_DEV_SCSIREG_H)
123 # define USE OPENSTEP_INTERFACE
124 # include <bsd/dev/scsireg.h>
125 #elif defined (HAVE_IO_CAM_CAM_H)
126 # define USE DECUNIX_INTERFACE
127 # include <io/common/iotypes.h>
128 # include <io/cam/cam.h>
129 # include <io/cam/dec_cam.h>
130 # include <io/cam/uagt.h>
131 # include <io/cam/scsi_all.h>
132 #elif defined (HAVE_SYS_DSREQ_H)
133 # define USE IRIX_INTERFACE
134 # include <sys/dsreq.h>
135 # include <invent.h>
136 #elif defined (HAVE_SYS_SCSI_H)
137 # include <sys/scsi.h>
138 # ifdef HAVE_SYS_SDI_COMM_H
139 #  ifdef HAVE_SYS_PASSTHRUDEF_H
140 #   define USE SCO_UW71_INTERFACE
141 #   include <sys/scsi.h>
142 #   include <sys/sdi_edt.h>
143 #   include <sys/sdi.h>
144 #   include <sys/passthrudef.h>
145 #  else
146 #   define USE SYSVR4_INTERFACE	/* Unixware 2.x tested */
147 #   define HAVE_SYSV_DRIVER
148 #   include <sys/sdi_edt.h>
149 #   include <sys/sdi_comm.h>
150 #  endif
151 # else
152 #  ifdef SCTL_READ
153 #   define USE HPUX_INTERFACE
154 #  else
155 #   ifdef HAVE_GSCDDS_H
156 #    define USE AIX_GSC_INTERFACE
157 #    include <gscdds.h>
158 #   else
159     /* This happens for AIX without gsc and possibly other platforms... */
160 #   endif
161 #  endif
162 # endif
163 #elif defined (HAVE_OS2_H)
164 # define USE OS2_INTERFACE
165 # define INCL_DOSFILEMGR
166 # define INCL_DOS
167 # define INCL_DOSDEVICES
168 # define INCL_DOSDEVIOCTL
169 # define INCL_DOSMEMMGR
170 # include <os2.h>
171 # include "os2_srb.h"
172 #elif defined (HAVE_SYS_SCSI_SGDEFS_H)
173 # define USE SOLARIS_SG_INTERFACE
174 # include <sys/scsi/sgdefs.h>
175 #elif defined (HAVE_SYS_SCSI_TARGETS_SCGIO_H)
176 # define USE SOLARIS_INTERFACE
177 # define SOL2
178 # include <sys/scsi/targets/scgio.h>
179 #elif defined (HAVE_SYS_SCSI_SCSI_H)
180   /*
181    * the "official" solaris uscsi(7I) interface; comes last, so that users
182    * installing the SCG/SG driver can still use these generic scsi interfaces
183    */
184 # define USE SOLARIS_USCSI_INTERFACE
185 # define SOL2
186 # include <sys/scsi/scsi.h>
187 #elif defined (HAVE_APOLLO_SCSI_H)
188 # define USE DOMAINOS_INTERFACE
189 # include <signal.h>		/* Only used for signal name for KillDomainServer */
190 # include <apollo/base.h>
191 # include <apollo/ec2.h>
192 # include <apollo/error.h>
193 # include <apollo/ms.h>
194 # include <apollo/mutex.h>
195 # include <apollo/scsi.h>
196 # include <apollo/time.h>
197 # include "sanei_DomainOS.h"
198 #elif defined (HAVE_IOKIT_CDB_IOSCSILIB_H) || \
199       defined (HAVE_IOKIT_SCSI_SCSICOMMANDOPERATIONCODES_H) || \
200       defined (HAVE_IOKIT_SCSI_COMMANDS_SCSICOMMANDOPERATIONCODES_H)
201 # define USE MACOSX_INTERFACE
202 # include <CoreFoundation/CoreFoundation.h>
203 # include <IOKit/IOKitLib.h>
204 # ifdef HAVE_IOKIT_CDB_IOSCSILIB_H
205 #  include <IOKit/IOCFPlugIn.h>
206 #  include <IOKit/cdb/IOSCSILib.h>
207 # endif
208 # ifdef HAVE_IOKIT_SCSI_SCSICOMMANDOPERATIONCODES_H
209 /* The def of VERSION causes problems in the following include files */
210 #  undef VERSION
211 #  include <IOKit/scsi/SCSICmds_INQUIRY_Definitions.h>
212 #  include <IOKit/scsi/SCSICommandOperationCodes.h>
213 #  include <IOKit/scsi/SCSITaskLib.h>
214 # else
215 # ifdef HAVE_IOKIT_SCSI_COMMANDS_SCSICOMMANDOPERATIONCODES_H
216 /* The def of VERSION causes problems in the following include files */
217 #  undef VERSION
218 #  include <IOKit/scsi-commands/SCSICmds_INQUIRY_Definitions.h>
219 #  include <IOKit/scsi-commands/SCSICommandOperationCodes.h>
220 #  include <IOKit/scsi-commands/SCSITaskLib.h>
221 # endif
222 # endif
223 #elif defined (HAVE_DDK_NTDDSCSI_H)
224 # define USE WIN32_INTERFACE
225 # include <ddk/scsi.h>
226 # include <ddk/ntddscsi.h>
227 #elif defined (HAVE_NTDDSCSI_H)
228 # define USE WIN32_INTERFACE
229 # include <ntddscsi.h>
230 #endif
231 
232 #ifndef USE
233 # define USE STUBBED_INTERFACE
234 #endif
235 
236 #if USE == LINUX_INTERFACE
237 # include <dirent.h>
238 #endif
239 
240 #include "../include/sane/sanei.h"
241 #include "../include/sane/sanei_config.h"
242 #include "../include/sane/sanei_scsi.h"
243 
244 #define BACKEND_NAME	sanei_scsi
245 #include "../include/sane/sanei_debug.h"
246 
247 #if USE == DECUNIX_INTERFACE
248 static int cam_fd = -1;		/* used for SCSI CAM based interfaces */
249 #endif
250 
251 #if USE == SOLARIS_INTERFACE || USE == SOLARIS_USCSI_INTERFACE
252 static int unit_ready (int fd);
253 #endif
254 
255 #ifdef SG_BIG_BUFF
256 # define MAX_DATA	SG_BIG_BUFF
257 #endif
258 
259 #if USE == SYSVR4_INTERFACE
260 # define MAX_DATA 56*1024	/* don't increase or kernel will dump
261 				 * tested with adsl, adsa and umax backend
262 				 * it depends on the lowend scsi
263 				 * drivers . But the most restriction
264 				 * is in the UNIXWARE KERNEL witch do
265 				 * not allow more then 64kB DMA transfers */
266 static char lastrcmd[16];	/* hold command block of last read command */
267 #endif
268 
269 #if USE == OPENSTEP_INTERFACE
270 # define MAX_DATA	(120*1024)
271 #endif
272 
273 #if USE == IRIX_INTERFACE
274 # define MAX_DATA	(256*1024)
275 #endif
276 
277 #if USE == FREEBSD_CAM_INTERFACE
278 # define MAX_DATA	(DFLTPHYS - PAGE_SIZE)
279 #endif
280 
281 #if USE == SOLARIS_INTERFACE
282 # define MAX_DATA	(128*1024)
283 #endif
284 
285 #if USE == SOLARIS_SG_INTERFACE
286 # define MAX_DATA	(128*1024)
287 #endif
288 
289 #if USE == SOLARIS_USCSI_INTERFACE
290 # define MAX_DATA	(64*1024)
291 #endif
292 
293 #if USE == OS2_INTERFACE
294 # define MAX_DATA	(64*1024)
295 #endif
296 
297 #if USE == MACOSX_INTERFACE
298 # define MAX_DATA	(128*1024)
299 #endif
300 
301 
302 #ifndef MAX_DATA
303 # define MAX_DATA	(32*1024)
304 #endif
305 
306 #ifdef SG_SET_TIMEOUT
307 # ifdef _SC_CLK_TCK
308 #  define GNU_HZ  sysconf(_SC_CLK_TCK)
309 # else
310 #  ifdef HZ
311 #   define GNU_HZ  HZ
312 #  else
313 #   ifdef CLOCKS_PER_SEC
314 #    define GNU_HZ  CLOCKS_PER_SEC
315 #   endif
316 #  endif
317 # endif
318 #endif
319 
320 /* default timeout value: 120 seconds */
321 static int sane_scsicmd_timeout = 120;
322 int sanei_scsi_max_request_size = MAX_DATA;
323 #if USE == LINUX_INTERFACE
324 /* the following #defines follow Douglas Gilbert's sample code
325    to maintain run time compatibility with the old and the
326    new SG driver for Linux
327 */
328 #include "linux_sg3_err.h"	/* contains several definitions of error codes */
329 #ifndef SG_SET_COMMAND_Q
330 #define SG_SET_COMMAND_Q 0x2271
331 #endif
332 #ifndef SG_SET_RESERVED_SIZE
333 #define SG_SET_RESERVED_SIZE 0x2275
334 #endif
335 #ifndef SG_GET_RESERVED_SIZE
336 #define SG_GET_RESERVED_SIZE 0x2272
337 #endif
338 #ifndef SG_GET_SCSI_ID
339 #define SG_GET_SCSI_ID 0x2276
340 #else
341 #define SG_GET_SCSI_ID_FOUND
342 #endif
343 #ifndef SG_GET_VERSION_NUM
344 #define SG_GET_VERSION_NUM 0x2282
345 #endif
346 #ifndef SG_NEXT_CMD_LEN
347 #define SG_NEXT_CMD_LEN 0x2283
348 #endif
349 
350 #ifndef SCSIBUFFERSIZE
351 #define SCSIBUFFERSIZE (128 * 1024)
352 #endif
353 
354 /* the struct returned by the SG ioctl call SG_GET_SCSI_ID changed
355    from version 2.1.34 to 2.1.35, and we need the information from
356    the field s_queue_depth, which was introduced in 2.1.35.
357    To get this file compiling also with older versions of sg.h, the
358    struct is re-defined here.
359 */
360 typedef struct xsg_scsi_id
361 {
362   int host_no;			/* as in "scsi<n>" where 'n' is one of 0, 1, 2 etc */
363   int channel;
364   int scsi_id;			/* scsi id of target device */
365   int lun;
366   int scsi_type;		/* TYPE_... defined in scsi/scsi.h */
367   short h_cmd_per_lun;		/* host (adapter) maximum commands per lun */
368   short d_queue_depth;		/* device (or adapter) maximum queue length */
369   int unused1;			/* probably find a good use, set 0 for now */
370   int unused2;			/* ditto */
371 }
372 SG_scsi_id;
373 
374 typedef struct req
375 {
376   struct req *next;
377   int fd;
378   u_int running:1, done:1;
379   SANE_Status status;
380   size_t *dst_len;
381   void *dst;
382 /* take the definition of the ioctl parameter SG_IO as a
383    compiler flag if the new SG driver is available
384 */
385   union
386   {
387     struct
388     {
389       struct sg_header hdr;
390       /* Make sure this is the last element, the real size is
391          SG_BIG_BUFF and machine dependent */
392       u_int8_t data[1];
393     }
394     cdb;
395 #ifdef SG_IO
396 /* at present, Linux's SCSI system limits the sense buffer to 16 bytes
397    which is definitely too small. Hoping that this will change at some time,
398    let's set the sense buffer size to 64.
399 */
400 #define SENSE_MAX 64
401 #define MAX_CDB 12
402     struct
403     {
404       struct sg_io_hdr hdr;
405       u_char sense_buffer[SENSE_MAX];
406       u_int8_t data[1];
407     }
408     sg3;
409 #endif
410   }
411   sgdata;
412 }
413 req;
414 
415 typedef struct Fdparms
416 {
417   int sg_queue_used, sg_queue_max;
418   size_t buffersize;
419   req *sane_qhead, *sane_qtail, *sane_free_list;
420 }
421 fdparms;
422 
423 #endif
424 
425 #if USE == FREEBSD_CAM_INTERFACE
426 # define CAM_MAXDEVS	128
427 struct cam_device *cam_devices[CAM_MAXDEVS] = { NULL };
428 #endif
429 
430 static struct
431 {
432   u_int in_use:1;		/* is this fd_info in use? */
433   u_int fake_fd:1;		/* is this a fake file descriptor? */
434   u_int bus, target, lun;	/* nexus info; used for some interfaces only */
435   SANEI_SCSI_Sense_Handler sense_handler;
436   void *sense_handler_arg;
437   void *pdata;			/* platform-specific data */
438 }
439  *fd_info;
440 
441 static u_char cdb_sizes[8] = {
442   6, 10, 10, 12, 12, 12, 10, 10
443 };
444 #define CDB_SIZE(opcode)	cdb_sizes[(((opcode) >> 5) & 7)]
445 
446 
447 #if USE == DOMAINOS_INTERFACE
448 
449 /*
450    This includes the server code.  Most of these routines are private to the
451    actual server.  The only public ones are:
452    sanei_DomainOS_init     Used to initialize the server
453    DomainErrorCheck        A common error handling routine
454  */
455 
456 #include "sanei_DomainOS.c"
457 
458 int ServerInitialized = 0;
459 pid_t ServerPID;
460 struct DomainServerCommon *com;
461 long CommandTriggerValue[2];
462 ec2_$ptr_t CommandAcceptedPtr[2];
463 long ResultTriggerValue[2];
464 ec2_$ptr_t ResultReadyPtr[2];
465 time_$clock_t Wait16S = { 64, 0 };	/* Delay of about 16 Seconds */
466 
467 
468 /* This function is registered as an exit function.  It's purpose is
469    to make sure that the Domain SANE Server is stopped.  It tries to
470    send an Exit command, and if that fails, it will send SIGQUIT to
471    the server.  It will also unmap the common area before it
472    returns. */
473 static void
KillDomainServer(void)474 KillDomainServer (void)
475 {
476   static boolean GotTheLock;
477   static status_$t status;
478   static pinteger index;
479 
480   DBG (1, "Asking Domain SANE Server to exit\n");
481   /* First, try to send a command to exit */
482   if (GotTheLock = mutex_$lock (&com->CommandLock, Wait16S))
483     {
484       /* Set the wait time to 16 Seconds (units are 4uS) */
485       com->opcode = Exit;
486       CommandTriggerValue[0] = ec2_$read (com->CommandAccepted) + 1;
487       ec2_$advance (&com->CommandAvailable, &status);
488       DomainErrorCheck (status, "Can't advance CommandAvailable EC");
489       /* For this wait, we want to allow a timeout as well */
490       CommandTriggerValue[1] = (ec2_$read (*CommandAcceptedPtr[1])
491 				+ DomainECWaitConstant);
492       index = ec2_$wait_svc (CommandAcceptedPtr, CommandTriggerValue, 2,
493 			     &status);
494       DomainErrorCheck (status,
495 			"Error waiting on Exit command acceptance EC");
496       /* Release the lock */
497       mutex_$unlock (&com->CommandLock);
498       if (index == 1)
499 	DBG (1, "Domain SANE Server responded to exit request\n");
500       else
501 	DBG (1, "Domain SANE Server did not respond to exit request\n");
502     }
503   else
504     DBG (0, "Could not get mutex lock for killing server\n");
505   if ((!GotTheLock) || (index != 1))
506     {
507       /* If we get here, then we never got the mutex lock, or we timed out
508          waiting for an Exit command ack. */
509       /* It's now time to be brutal with the server */
510       DBG (1, "Sending QUIT signal to Domain SANE Server\n");
511       kill (ServerPID, SIGQUIT);
512     }
513   /* unmap the common area */
514   ms_$unmap (com, sizeof (struct DomainServerCommon), &status);
515   DomainErrorCheck (status, "Error unmapping common area");
516 }
517 #endif /* USE == DOMAINOS_INTERFACE */
518 
519 
520 #if USE == OS2_INTERFACE
521 
522 /* Driver info:  */
523 static HFILE driver_handle = 0;	/* file handle for device driver */
524 static PVOID aspi_buf = 0;	/* Big data buffer locked by driver. */
525 static int aspi_ref_count = 0;	/* # of fds using ASPI */
526 static SRB *PSRBlock = 0;	/* SCSI Request Block */
527 static char tmpAspi[MAXPATHLEN];	/* scsi chain scan */
528 #define INQUIRY					0x12
529 #define set_inquiry_return_size(icb,val)	icb[0x04]=val
530 #define IN_periph_devtype_cpu			0x03
531 #define IN_periph_devtype_scanner		0x06
532 #define get_inquiry_vendor(in, buf)		strncpy(buf, in + 0x08, 0x08)
533 #define get_inquiry_product(in, buf)		strncpy(buf, in + 0x10, 0x010)
534 #define get_inquiry_version(in, buf)		strncpy(buf, in + 0x20, 0x04)
535 #define get_inquiry_periph_devtype(in)		(in[0] & 0x1f)
536 #define get_inquiry_additional_length(in)	in[0x04]
537 #define set_inquiry_length(out,n)		out[0x04]=n-5
538 
539 /* Open OS2 ASPI driver.
540 
541    Output: 0 if error, which is reported.  */
542 static int
open_aspi(void)543 open_aspi (void)
544 {
545   ULONG rc;
546   ULONG ActionTaken;
547   USHORT lockSegmentReturn;
548   unsigned long cbreturn = 0;
549   unsigned long cbParam = 0;
550   int i, num_adapters;		/* no. of scsi adapters installed */
551 
552   char *devtypes[] = {
553     "disk", "tape", "printer", "processor", "CD-writer",
554     "CD-drive", "scanner", "optical-drive", "jukebox",
555     "communicator"
556   };
557   FILE *tmp;
558 
559   if (driver_handle)
560     {
561       aspi_ref_count++;		/* increment internal usage counter */
562       return 1;			/* Already open. */
563     }
564   aspi_buf = _tcalloc (sanei_scsi_max_request_size, 1);
565   if (aspi_buf == NULL)
566     {
567       DBG (1, "sanei_scsi_open_aspi: _tcalloc aspi_buf failed");
568       return 0;
569     }
570 
571   PSRBlock = _tcalloc (sizeof (SRB), 1);
572   if (PSRBlock == NULL)
573     {
574       DBG (1, "sanei_scsi_open_aspi: _tcalloc PSRBlock failed");
575       return 0;
576     }
577 
578   rc = DosOpen ((PSZ) "aspirou$",	/* open driver */
579 		&driver_handle,
580 		&ActionTaken,
581 		0,
582 		0,
583 		FILE_OPEN,
584 		OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE, NULL);
585   if (rc)
586     {
587       /* opening failed -> return false */
588       DBG (1, "open_aspi:  opening failed.\n");
589       return 0;
590     }
591 
592   /* Lock aspi_buf. */
593   rc = DosDevIOCtl (driver_handle, 0x92, 0x04,	/* pass aspi_buf pointer */
594 		    (void *) aspi_buf, sizeof (PVOID),	/* to driver */
595 		    &cbParam, (void *) &lockSegmentReturn,
596 		    sizeof (USHORT), &cbreturn);
597   if (rc || lockSegmentReturn)
598     {
599       /* DosDevIOCtl failed */
600       DBG (1, "sanei_scsi_open_aspi:  Can't lock buffer. rc= %lu \n", rc);
601       return 0;
602     }
603 
604   /* query number of installed adapters */
605   memset (PSRBlock, 0, sizeof (SRB));
606   PSRBlock->cmd = SRB_Inquiry;	/* host adapter inquiry */
607 
608   PSRBlock->ha_num = 0;		/* host adapter number */
609 
610   PSRBlock->flags = 0;		/* no flags set */
611 
612   rc = DosDevIOCtl (driver_handle, 0x92, 0x02,
613 		    (void *) PSRBlock, sizeof (SRB), &cbParam,
614 		    (void *) PSRBlock, sizeof (SRB), &cbreturn);
615   num_adapters = PSRBlock->u.inq.num_ha;
616 
617   DBG (1, "OS/2: installed adapters %d\n", num_adapters);
618   DBG (1, "OS/2: ASPI manager is '%s'\n", PSRBlock->u.inq.aspimgr_id);
619   DBG (1, "OS/2: host adapter is '%s'\n", PSRBlock->u.inq.host_id);
620   DBG (1, "OS/2: unique id is    '%s'\n", PSRBlock->u.inq.unique_id);
621 
622   strcpy (tmpAspi, "asXXXXXX");
623   mkstemp (tmpAspi);
624   DBG (2, "open_aspi: open temporary file '%s'\n", tmpAspi);
625   tmp = fopen (tmpAspi, "w");
626   if (!tmp)
627     {				/* can't open tmp file */
628 
629       DBG (1, "open_aspi:  Can't open temporary file.\n");
630       return 0;
631     }
632 
633   /* scan all installed adapters */
634   for (i = 0; i < num_adapters; i++)
635     {
636       int id;
637       /* query adapter name */
638       memset (PSRBlock, 0, sizeof (SRB));
639       PSRBlock->cmd = SRB_Inquiry;	/* host adapter inquiry */
640 
641       PSRBlock->ha_num = i;	/* host adapter number */
642 
643       PSRBlock->flags = 0;	/* no flags set */
644 
645       rc = DosDevIOCtl (driver_handle, 0x92, 0x02,
646 			(void *) PSRBlock, sizeof (SRB), &cbParam,
647 			(void *) PSRBlock, sizeof (SRB), &cbreturn);
648       DBG (1, "OS/2: adapter#%02d '%s'\n", i, PSRBlock->u.inq.host_id);
649 
650       /* scan scsi chain (need 15 for wide?) */
651       for (id = 0; id < 7; id++)
652 	{
653 	  unsigned char len;
654 	  char vendor[9];
655 	  char product[17];
656 	  char version[5];
657 	  char *pp;
658 
659 	  memset (PSRBlock, 0, sizeof (SRB));
660 	  PSRBlock->cmd = SRB_Device;	/* get device type */
661 
662 	  PSRBlock->ha_num = i;	/* host adapter number */
663 
664 	  PSRBlock->flags = 0;	/* no flags set */
665 
666 	  PSRBlock->u.dev.target = id;	/* target id */
667 
668 	  PSRBlock->u.dev.lun = 0;	/* target LUN */
669 
670 	  rc = DosDevIOCtl (driver_handle, 0x92, 0x02,
671 			    (void *) PSRBlock, sizeof (SRB), &cbParam,
672 			    (void *) PSRBlock, sizeof (SRB), &cbreturn);
673 	  DBG (1, "OS/2:             id#%02d status=%02xh\n",
674 	       id, PSRBlock->status);
675 
676 	  /* skip if device not connected */
677 	  if (PSRBlock->status == SRB_BadDevice)
678 	    continue;
679 
680 	  DBG (1, "OS/2:                   type is '%s'\n",
681 	       PSRBlock->u.dev.devtype < sizeof (devtypes) / sizeof (char *)?
682 	       devtypes[PSRBlock->u.dev.devtype] : "unknown device");
683 
684 	  /* query adapter string id */
685 	  memset (PSRBlock, 0, sizeof (SRB));
686 	  PSRBlock->cmd = SRB_Command;	/* execute SCSI command */
687 
688 	  PSRBlock->ha_num = i;	/* host adapter number */
689 	  PSRBlock->flags = SRB_Read | SRB_Post;	/* data transfer, posting */
690 	  PSRBlock->u.cmd.target = id;	/* Target SCSI ID */
691 	  PSRBlock->u.cmd.lun = 0;	/* Target SCSI LUN */
692 	  PSRBlock->u.cmd.data_len = 5;	/* # of bytes transferred */
693 	  PSRBlock->u.cmd.sense_len = 32;	/* length of sense buffer */
694 	  PSRBlock->u.cmd.data_ptr = NULL;	/* pointer to data buffer */
695 	  PSRBlock->u.cmd.link_ptr = NULL;	/* pointer to next SRB */
696 	  PSRBlock->u.cmd.cdb_len = 6;	/* SCSI command length */
697 	  PSRBlock->u.cmd.cdb_st[0] = INQUIRY;	/* inquiry command */
698 	  PSRBlock->u.cmd.cdb_st[1] = 0;	/* ?? length */
699 	  PSRBlock->u.cmd.cdb_st[2] = 0;	/* transfer length MSB */
700 	  PSRBlock->u.cmd.cdb_st[3] = 0;	/* transfer length */
701 	  PSRBlock->u.cmd.cdb_st[4] = 5;	/* transfer length LSB */
702 	  PSRBlock->u.cmd.cdb_st[5] = 0;
703 	  rc = DosDevIOCtl (driver_handle, 0x92, 0x02,
704 			    (void *) PSRBlock, sizeof (SRB), &cbParam,
705 			    (void *) PSRBlock, sizeof (SRB), &cbreturn);
706 	  len = ((char *) aspi_buf)[4];	/* additional length */
707 
708 	  /* query id string */
709 	  memset (PSRBlock, 0, sizeof (SRB));
710 	  PSRBlock->cmd = SRB_Command;	/* execute SCSI command */
711 	  PSRBlock->ha_num = i;	/* host adapter number */
712 	  PSRBlock->flags = SRB_Read | SRB_Post;	/* data transfer, posting */
713 	  PSRBlock->u.cmd.target = id;	/* Target SCSI ID */
714 	  PSRBlock->u.cmd.lun = 0;	/* Target SCSI LUN */
715 	  PSRBlock->u.cmd.data_len = 5 + len;	/* # of bytes transferred */
716 	  PSRBlock->u.cmd.sense_len = 32;	/* length of sense buffer */
717 	  PSRBlock->u.cmd.data_ptr = NULL;	/* pointer to data buffer */
718 	  PSRBlock->u.cmd.link_ptr = NULL;	/* pointer to next SRB */
719 	  PSRBlock->u.cmd.cdb_len = 6;	/* SCSI command length */
720 	  PSRBlock->u.cmd.cdb_st[0] = 0x12;	/* inquiry command */
721 	  PSRBlock->u.cmd.cdb_st[1] = 0;	/* ?? length */
722 	  PSRBlock->u.cmd.cdb_st[2] = 0;	/* transfer length MSB */
723 	  PSRBlock->u.cmd.cdb_st[3] = 0;	/* transfer length */
724 	  PSRBlock->u.cmd.cdb_st[4] = 5 + len;	/* transfer length LSB */
725 	  PSRBlock->u.cmd.cdb_st[5] = 0;
726 	  rc = DosDevIOCtl (driver_handle, 0x92, 0x02,
727 			    (void *) PSRBlock, sizeof (SRB), &cbParam,
728 			    (void *) PSRBlock, sizeof (SRB), &cbreturn);
729 	  DBG (1, "OS/2         '%s'\n", (char *) aspi_buf + 8);
730 	  /* write data */
731 	  get_inquiry_vendor ((char *) aspi_buf, vendor);
732 	  get_inquiry_product ((char *) aspi_buf, product);
733 	  get_inquiry_version ((char *) aspi_buf, version);
734 
735 	  pp = &vendor[7];
736 	  vendor[8] = '\0';
737 	  while (pp >= vendor && (*pp == ' ' || *pp >= 127))
738 	    *pp-- = '\0';
739 
740 	  pp = &product[15];
741 	  product[16] = '\0';
742 	  while (pp >= product && (*pp == ' ' || *pp >= 127))
743 	    *pp-- = '\0';
744 
745 	  pp = product;
746 	  do
747 	    {
748 	      if (isspace ((int) *pp))
749 		*pp = '_';
750 	    }
751 	  while (*++pp);
752 
753 	  pp = &version[3];
754 	  version[4] = '\0';
755 	  while (pp >= version && (*pp == ' ' || *(pp - 1) >= 127))
756 	    *pp-- = '\0';
757 	  fprintf (tmp, "Vendor: %s ", vendor);
758 	  fprintf (tmp, "Model: %s ", product);
759 	  fprintf (tmp, "Rev: %s ", version);
760 	  fprintf (tmp, "scsi %d Channel: 0 Id: %d Lun: 0\n", i, id);
761 	}
762     }
763   DBG (2, "open_aspi: close temporary file '%s'\n", tmpAspi);
764   fclose (tmp);
765 
766   aspi_ref_count++;		/* increment internal usage counter */
767 
768   return 1;
769 }
770 
771 /* Close driver and free everything.  */
772 
773 static void
close_aspi(void)774 close_aspi (void)
775 {
776   aspi_ref_count--;		/* decrement internal usage counter */
777 
778   if (aspi_ref_count)
779     return;			/* wait for usage==0 */
780 
781   if (driver_handle)		/* Close driver. */
782     DosClose (driver_handle);
783   driver_handle = 0;
784   if (aspi_buf)			/* Free buffer. */
785     _tfree (aspi_buf);
786   aspi_buf = 0;
787 
788   if (PSRBlock)
789     _tfree (PSRBlock);
790   PSRBlock = 0;
791 
792   errno = 0;
793   if (unlink (tmpAspi))		/* remove scsi descriptions */
794     DBG (2, "OS/2: error#%d while removing temporary '%s'\n", errno, tmpAspi);
795   strcpy (tmpAspi, "");
796 
797   DBG (1, "OS/2: ASPI closed\n");
798 }
799 
800 #endif /* USE_OS2_INTERFACE */
801 
802 static int num_alloced = 0;
803 
804 #if USE == LINUX_INTERFACE
805 
806 static int sg_version = 0;
807 
808 static SANE_Status
get_max_buffer_size(const char * file)809 get_max_buffer_size (const char *file)
810 {
811   int fd = -1;
812   int buffersize = SCSIBUFFERSIZE, i;
813   size_t len;
814   char *cc, *cc1, buf[32];
815 
816 #ifdef HAVE_RESMGR
817   fd = rsm_open_device(file, O_RDWR);
818 #endif
819 
820   if (fd == -1)
821     fd = open (file, O_RDWR);
822 
823   if (fd > 0)
824     {
825       cc = getenv ("SANE_SG_BUFFERSIZE");
826       if (cc)
827 	{
828 	  i = strtol (cc, &cc1, 10);
829 	  if (cc != cc1 && i >= 32768)
830 	    buffersize = i;
831 	}
832 
833       ioctl (fd, SG_SET_RESERVED_SIZE, &buffersize);
834       if (0 == ioctl (fd, SG_GET_RESERVED_SIZE, &buffersize))
835 	{
836 	  if (buffersize < sanei_scsi_max_request_size)
837 	    sanei_scsi_max_request_size = buffersize;
838 	  close (fd);
839 	  DBG (4, "get_max_buffer_size for %s: %i\n", file,
840 	       sanei_scsi_max_request_size);
841 	  return SANE_STATUS_GOOD;
842 	}
843       else
844 	{
845 	  close (fd);
846 	  /* ioctl not available: we have the old SG driver */
847 	  fd = open ("/proc/sys/kernel/sg-big-buff", O_RDONLY);
848 	  if (fd > 0 && (len = read (fd, buf, sizeof (buf) - 1)) > 0)
849 	    {
850 	      buf[len] = '\0';
851 	      sanei_scsi_max_request_size = atoi (buf);
852 	      close (fd);
853 	    }
854 	  else
855 	    sanei_scsi_max_request_size = buffersize < SG_BIG_BUFF ?
856 	      buffersize : SG_BIG_BUFF;
857 	  return SANE_STATUS_IO_ERROR;
858 	}
859     }
860   else
861     return SANE_STATUS_GOOD;
862 }
863 
864 
865 SANE_Status
sanei_scsi_open_extended(const char * dev,int * fdp,SANEI_SCSI_Sense_Handler handler,void * handler_arg,int * buffersize)866 sanei_scsi_open_extended (const char *dev, int *fdp,
867 			  SANEI_SCSI_Sense_Handler handler,
868 			  void *handler_arg, int *buffersize)
869 #else
870 
871 SANE_Status
872 sanei_scsi_open (const char *dev, int *fdp,
873 		 SANEI_SCSI_Sense_Handler handler, void *handler_arg)
874 #endif
875 {
876   u_int bus = 0, target = 0, lun = 0, fake_fd = 0;
877   char *real_dev = 0;
878   void *pdata = 0;
879   char *cc, *cc1;
880   int fd, i;
881 #if USE == LINUX_INTERFACE
882   static int first_time = 1;
883 #elif USE == MACOSX_INTERFACE
884   UInt8 *guid;
885   int len;
886   u_int d;
887 #endif
888 
889   cc = getenv ("SANE_SCSICMD_TIMEOUT");
890   if (cc)
891     {
892       i = strtol (cc, &cc1, 10);
893       /* 20 minutes are hopefully enough as a timeout value ;) */
894       if (cc != cc1 && i > 0 && i <= 1200)
895 	{
896 	  sane_scsicmd_timeout = i;
897 	}
898       else
899 	{
900 	  DBG (1,
901 	       "sanei_scsi_open: timeout value must be between 1 and 1200 seconds\n");
902 	}
903     }
904 
905   DBG_INIT ();
906 
907 #if USE == LINUX_INTERFACE
908   if (first_time)
909     {
910       first_time = 0;
911 
912       /* Try to determine a reliable value for sanei_scsi_max_request_size:
913 
914          With newer versions of the SG driver, check the available buffer
915          size by opening all SG device files belonging to a scanner,
916          issue the ioctl calls for setting and reading the reserved
917          buffer size, and take the smallest value.
918 
919          For older version of the SG driver, which don't support variable
920          buffer size, try to read /proc/sys/kernel/sg-big-biff ; if
921          this fails (SG driver too old, or loaded as a module), use
922          SG_BIG_BUFF
923        */
924 
925       sanei_scsi_max_request_size = SCSIBUFFERSIZE;
926       cc = getenv ("SANE_SG_BUFFERSIZE");
927       if (cc)
928 	{
929 	  i = strtol (cc, &cc1, 10);
930 	  if (cc != cc1 && i >= 32768)
931 	    sanei_scsi_max_request_size = i;
932 	}
933       sanei_scsi_find_devices (0, 0, "Scanner", -1, -1, -1, -1,
934 			       get_max_buffer_size);
935       sanei_scsi_find_devices (0, 0, "Processor", -1, -1, -1, -1,
936 			       get_max_buffer_size);
937       DBG (4, "sanei_scsi_open: sanei_scsi_max_request_size=%d bytes\n",
938 	   sanei_scsi_max_request_size);
939     }
940 #endif
941 
942 #if USE == OS2_INTERFACE
943   if (sscanf (dev, "b%ut%ul%u", &bus, &target, &lun) != 3)
944     {
945       DBG (1, "sanei_scsi_open: device name %s is not valid\n", dev);
946       return SANE_STATUS_INVAL;
947     }
948   if (!open_aspi ())
949     {
950       /* Open driver if necessary. */
951       close_aspi ();
952       return SANE_STATUS_INVAL;
953     }
954 
955   /* Find fake fd. */
956   for (fd = 0; fd < num_alloced; ++fd)
957     if (!fd_info[fd].in_use)
958       break;
959   fake_fd = 1;
960 #elif USE == DECUNIX_INTERFACE
961   {
962     UAGT_CAM_SCAN cam_scan;
963 
964     if (sscanf (dev, "b%dt%dl%d", &bus, &target, &lun) != 3)
965       {
966 	DBG (1, "sanei_scsi_open: device name `%s´ is not valid: %s\n",
967 	     dev, strerror (errno));
968 	return SANE_STATUS_INVAL;
969       }
970 
971     if (cam_fd < 0)
972       {
973 	cam_fd = open ("/dev/cam", O_RDWR);
974 	if (cam_fd < 0)
975 	  {
976 	    DBG (1, "sanei_scsi_open: open(/dev/cam) failed: %s\n",
977 		 strerror (errno));
978 	    return SANE_STATUS_INVAL;
979 	  }
980       }
981     cam_scan.ucs_bus = bus;
982     cam_scan.ucs_target = target;
983     cam_scan.ucs_lun = lun;
984     if (ioctl (cam_fd, UAGT_CAM_SINGLE_SCAN, &cam_scan) < 0)
985       {
986 	DBG (1, "sanei_scsi_open: ioctl(UAGT_CAM_SINGLE_SCAN) failed: %s\n",
987 	     strerror (errno));
988 	return SANE_STATUS_INVAL;
989       }
990 
991     for (fd = 0; fd < num_alloced; ++fd)
992       if (!fd_info[fd].in_use)
993 	break;
994     fake_fd = 1;
995   }
996 #elif USE == DOMAINOS_INTERFACE
997   {
998     static int index;
999     static status_$t status;
1000     static unsigned long length_mapped;
1001 
1002     DBG (1, "sanei_scsi_open: (dev='%s', int * fdp=%p, "
1003 	 "SANEI_SCSI_Sense_Handler handler=%p)\n", dev, fdp, handler);
1004 
1005     /* See if the server process has started yet */
1006     if (!ServerInitialized)
1007       {
1008 	static char *CommonAreaPath;
1009 
1010 	/* Initialize the server */
1011 	DBG (2, "Initializing Domain Server\n");
1012 
1013 	/* Map the area */
1014 	CommonAreaPath = tmpnam (NULL);
1015 	DBG (2, "Domain Server Common area name is '%s'\n", CommonAreaPath);
1016 	com = ms_$crmapl (CommonAreaPath, strlen (CommonAreaPath), 0,
1017 			  sizeof (struct DomainServerCommon), ms_$cowriters,
1018 			  &status);
1019 	DomainErrorCheck (status, "Can't open common area");
1020 	DBG (2, "Domain Server common area mapped\n");
1021 
1022 	/* Initialize the eventcounts */
1023 	ec2_$init (&com->CommandAvailable);
1024 	ec2_$init (&com->CommandAccepted);
1025 	ec2_$init (&com->ResultReady);
1026 	ec2_$init (&com->ResultAccepted);
1027 	DBG (2, "Domain Server EC's initialized\n");
1028 	/* Initialize the mutex locks */
1029 	mutex_$init (&com->CommandLock);
1030 	mutex_$init (&com->ResultLock);
1031 	DBG (2, "Domain Server MutexLock's initialized\n");
1032 
1033 	/* Initialize pointers to ECs */
1034 	CommandAcceptedPtr[0] = &com->CommandAccepted;
1035 	ResultReadyPtr[0] = &com->ResultReady;
1036 	time_$get_ec (time_$clockh_key, &CommandAcceptedPtr[1], &status);
1037 	DomainErrorCheck (status, "Can't get time EC");
1038 	ResultReadyPtr[1] = CommandAcceptedPtr[1];
1039 
1040 	/* Read the ResultReady EC value, to avoid race with the server */
1041 	ResultTriggerValue[0] = ec2_$read (com->ResultReady) + 1;
1042 
1043 	/* Now invoke the server */
1044 	ServerPID = fork ();
1045 	if (!ServerPID)
1046 	  {
1047 	    /* I am the child, call the initialization routine */
1048 	    sanei_DomainOS_init (CommonAreaPath);
1049 	    /* We get here when the server is done, so we just exit. */
1050 	    exit (EXIT_SUCCESS);
1051 	  }
1052 
1053 	/* The communication area is open, wait for the initial response */
1054 	ResultTriggerValue[1] = (ec2_$read (*ResultReadyPtr[1])
1055 				 + DomainECWaitConstant);
1056 	index =
1057 	  ec2_$wait_svc (ResultReadyPtr, ResultTriggerValue, 2, &status);
1058 	DomainErrorCheck (status, "Error waiting on initial open EC");
1059 	if (index != 1)
1060 	  {
1061 	    DBG (0, "Domain SANE Server never responded on startup\n");
1062 	    /* Send a quit signal to the server */
1063 	    kill (ServerPID, SIGQUIT);
1064 	    return SANE_STATUS_INVAL;
1065 	  }
1066 	/* Register a function to kill the server when we are done */
1067 	assert (!atexit (KillDomainServer));
1068 	ServerInitialized = 1;
1069       }
1070 
1071     /* Find fake fd. */
1072     for (fd = 0; fd < num_alloced; ++fd)
1073       if (!fd_info[fd].in_use)
1074 	break;
1075     fake_fd = 1;
1076 
1077     /* Send the command open to the server */
1078     if (!mutex_$lock (&com->CommandLock, Wait16S))
1079       {
1080 	DBG (0, "Could not obtain mutex lock for Open\n");
1081 	return SANE_STATUS_INVAL;
1082       }
1083     com->opcode = Open;
1084     strcpy (com->open_path, dev);
1085     CommandTriggerValue[0] = ec2_$read (com->CommandAccepted) + 1;
1086     ec2_$advance (&com->CommandAvailable, &status);
1087     DomainErrorCheck (status, "Can't advance CommandAvailable EC");
1088     CommandTriggerValue[1] = (ec2_$read (*CommandAcceptedPtr[1])
1089 			      + DomainECWaitConstant);
1090     index = ec2_$wait_svc (CommandAcceptedPtr, CommandTriggerValue, 2,
1091 			   &status);
1092     DomainErrorCheck (status, "Error waiting on Open command acceptance EC");
1093     if (index != 1)
1094       {
1095 	DBG (0, "Domain SANE Server never accepted Open Command\n");
1096 	return SANE_STATUS_INVAL;
1097       }
1098 
1099     /* Read the result */
1100     status = com->CommandStatus;
1101     DomainErrorCheck (status, "Opening device in server");
1102 
1103     /* Now map the data area, and make it temporary */
1104     DBG (2, "Mapping server's data block, name is '%s'\n", com->open_path);
1105     pdata = ms_$mapl (com->open_path, strlen (com->open_path), 0,
1106 		      DomainMaxDataSize + DomainSenseSize, ms_$cowriters,
1107 		      ms_$wr, true, &length_mapped, &status);
1108     DomainErrorCheck (status, "Mapping Server Data block");
1109     assert (length_mapped >= DomainMaxDataSize + DomainSenseSize);
1110     ms_$mk_temporary (pdata, &status);
1111     DomainErrorCheck (status, "Can't make data block temporary");
1112 
1113     /* Release the lock */
1114     mutex_$unlock (&com->CommandLock);
1115 
1116     if (status.all != status_$ok)
1117       {
1118 	/* we have a failure, return an error code, and generate debug
1119 	   output */
1120 	DBG (1, "sanei_scsi_open: acquire failed, Domain/OS status is %08x\n",
1121 	     status.all);
1122 	error_$print (status);
1123 	return SANE_STATUS_INVAL;
1124       }
1125     else
1126       {
1127 	/* device acquired, what else to do? */
1128 	fd = com->fd;
1129       }
1130   }
1131 #elif USE == FREEBSD_CAM_INTERFACE
1132   if (1)
1133     {				/* 'if(1) {' makes my emacs c-mode indent better than
1134 				   just '{' unfortunately, this only works if all of
1135 				   the '{' are that way. */
1136 
1137       struct cam_device *curdev;
1138 
1139       fake_fd = 1;
1140       fd = -1;
1141 
1142       if ((curdev = cam_open_pass (dev, O_RDWR, NULL)) != NULL)
1143 	{
1144 	  for (fd = 0; fd < CAM_MAXDEVS && cam_devices[fd] != NULL; fd++)
1145 	    ;
1146 
1147 	  if (fd == CAM_MAXDEVS)
1148 	    {
1149 	      DBG (1, "sanei_scsi_open: too many CAM devices (%d)\n", fd);
1150 	      cam_close_device (curdev);
1151 	      return SANE_STATUS_INVAL;
1152 	    }
1153 	  cam_devices[fd] = curdev;
1154 	}
1155       else
1156 	{
1157 	  DBG (1, "sanei_scsi_open: can't open device `%s´: %s\n", dev,
1158 	       strerror (errno));
1159 	  return SANE_STATUS_INVAL;
1160 	}
1161     }
1162 #elif USE == SCO_UW71_INTERFACE
1163   {
1164     pt_scsi_address_t dev_addr;
1165     pt_handle_t pt_handle;
1166     int bus, cnt, id, lun;
1167 
1168     if (4 !=
1169 	sscanf (dev, "/dev/passthru0:%d,%d,%d,%d", &bus, &cnt, &id, &lun))
1170       {
1171 	DBG (1, "sanei_scsi_open: device name `%s´ is not valid: %s\n",
1172 	     dev, strerror (errno));
1173 	return SANE_STATUS_INVAL;
1174       }
1175     dev_addr.psa_bus = bus;
1176     dev_addr.psa_controller = cnt;
1177     dev_addr.psa_target = id;
1178     dev_addr.psa_lun = lun;
1179 
1180     if (0 != pt_open (PASSTHRU_SCSI_ADDRESS, &dev_addr, PT_EXCLUSIVE,
1181 		      &pt_handle))
1182       {
1183 	DBG (1, "sanei_scsi_open: pt_open failed: %s!\n", strerror (errno));
1184 	return SANE_STATUS_INVAL;
1185       }
1186     else
1187       fd = (int) pt_handle;
1188   }
1189 #elif USE == MACOSX_INTERFACE
1190   {
1191 # if defined (HAVE_IOKIT_SCSI_SCSICOMMANDOPERATIONCODES_H) || \
1192      defined (HAVE_IOKIT_SCSI_COMMANDS_SCSICOMMANDOPERATIONCODES_H)
1193     len = strlen (dev);
1194     if (len > 2 && len % 2 == 0 && dev [0] == '<' && dev [len - 1] == '>')
1195       {
1196 	len = (len - 2) / 2;
1197 	guid = (UInt8 *) malloc (len);
1198 	for (i = 0; i < len; i++)
1199 	  {
1200 	    if (sscanf (&dev [2 * i + 1], "%02x", &d) != 1)
1201 	      break;
1202 	    guid [i] = d;
1203 	  }
1204 	if (i == len)
1205 	  pdata = (void *) CFDataCreate (kCFAllocatorDefault, guid, len);
1206 	free (guid);
1207       }
1208 # endif
1209 # ifdef HAVE_IOKIT_CDB_IOSCSILIB_H
1210     if ((pdata == NULL) &&
1211 	(sscanf (dev, "u%ut%ul%u", &bus, &target, &lun) != 3))
1212 # else
1213     if (pdata == NULL)
1214 # endif
1215       {
1216 	DBG (1, "sanei_scsi_open: device name %s is not valid\n", dev);
1217 	return SANE_STATUS_INVAL;
1218       }
1219 
1220     /* Find fake fd. */
1221     for (fd = 0; fd < num_alloced; ++fd)
1222       if (!fd_info[fd].in_use)
1223 	break;
1224     fake_fd = 1;
1225   }
1226 #elif USE == WIN32_INTERFACE
1227   {
1228 	  char scsi_hca_name[20];
1229 	  u_int hca = 0;
1230 
1231 	  if (sscanf (dev, "h%ub%ut%ul%u", &hca, &bus, &target, &lun) != 4)
1232 		  {
1233 			  DBG (1, "sanei_scsi_open: device name %s is not valid\n", dev);
1234 			  return SANE_STATUS_INVAL;
1235 		  }
1236 
1237 	  snprintf(scsi_hca_name, 19, "\\\\.\\Scsi%d:", hca);
1238 	  scsi_hca_name[19] = 0;
1239 
1240 	  fd = CreateFile(scsi_hca_name, GENERIC_READ | GENERIC_WRITE,
1241 					  FILE_SHARE_READ | FILE_SHARE_WRITE,
1242 					  NULL, OPEN_EXISTING,
1243 					  FILE_FLAG_RANDOM_ACCESS, NULL );
1244 
1245 	  if (fd == INVALID_HANDLE_VALUE) fd = -1;
1246   }
1247 #else
1248 #if defined(SGIOCSTL) || (USE == SOLARIS_INTERFACE)
1249   {
1250     size_t len;
1251 
1252     /* OpenStep and the Solaris SCG driver are a bit broken in that
1253        the device name refers to a scsi _bus_, not an individual scsi
1254        device.  Hence, SANE has to fudge with the device name so we
1255        know which target to connect to.  For this purpose, we use the
1256        last character in the device name as the target index.  'a' is
1257        target 0, 'b', target 1, and so on... */
1258 
1259     len = strlen (dev);
1260     if (len <= 1)
1261       {
1262 	DBG (1, "sanei_scsi_open: devicename `%s' too short\n", dev);
1263 	return SANE_STATUS_INVAL;
1264       }
1265 
1266     real_dev = strdup (dev);
1267     real_dev[len - 1] = '\0';
1268 
1269     target = dev[len - 1] - 'a';
1270     if (target > 7)
1271       {
1272 	DBG (1, "sanei_scsi_open: `%c' is not a valid target id\n",
1273 	     dev[len - 1]);
1274 	return SANE_STATUS_INVAL;
1275       }
1276     dev = real_dev;
1277   }
1278 #endif /* defined(SGIOCSTL) || (USE == SOLARIS_INTERFACE) */
1279 
1280   fd = -1;
1281 #ifdef HAVE_RESMGR
1282   fd = rsm_open_device(dev, O_RDWR | O_EXCL | O_NONBLOCK);
1283 #endif
1284 
1285   if (fd == -1)
1286     fd = open (dev, O_RDWR | O_EXCL
1287 #if USE == LINUX_INTERFACE
1288 	     | O_NONBLOCK
1289 #endif
1290     );
1291   if (fd < 0)
1292     {
1293       SANE_Status status = SANE_STATUS_INVAL;
1294 
1295       if (errno == EACCES)
1296 	status = SANE_STATUS_ACCESS_DENIED;
1297       else if (errno == EBUSY)
1298 	status = SANE_STATUS_DEVICE_BUSY;
1299 
1300       DBG (1, "sanei_scsi_open: open of `%s' failed: %s\n",
1301 	   dev, strerror (errno));
1302       return status;
1303     }
1304 
1305   if (real_dev)
1306     free (real_dev);
1307 
1308 #ifdef SG_SET_TIMEOUT
1309   /* Set large timeout since some scanners are slow but do not
1310      disconnect... ;-( */
1311   {
1312     int timeout;
1313     timeout = sane_scsicmd_timeout * GNU_HZ;
1314     ioctl (fd, SG_SET_TIMEOUT, &timeout);
1315   }
1316 #endif
1317 
1318 #ifdef SGIOCSTL
1319   {
1320     struct scsi_adr sa;
1321 
1322     sa.sa_target = target;
1323     sa.sa_lun = 0;
1324     if (ioctl (fd, SGIOCSTL, &sa) == -1)
1325       {
1326 	DBG (1, "sanei_scsi_open: failed to attach to target: %u (%s)\n",
1327 	     sa.sa_target, strerror (errno));
1328 	return SANE_STATUS_INVAL;
1329       }
1330   }
1331 #endif /* SGIOCSTL */
1332 #if USE == LINUX_INTERFACE
1333   {
1334     SG_scsi_id sid;
1335     int ioctl_val;
1336     int real_buffersize;
1337     fdparms *fdpa = 0;
1338     SG_scsi_id devinfo;
1339 
1340     pdata = fdpa = malloc (sizeof (fdparms));
1341     if (!pdata)
1342       {
1343 	close (fd);
1344 	return SANE_STATUS_NO_MEM;
1345       }
1346     memset (fdpa, 0, sizeof (fdparms));
1347     /* default: allow only one command to be sent to the SG driver
1348      */
1349     fdpa->sg_queue_max = 1;
1350 
1351     /* Try to read the SG version. If the ioctl call is successful,
1352        we have the new SG driver, and we can increase the buffer size
1353        using another ioctl call.
1354        If we have SG version 2.1.35 or above, we can additionally enable
1355        command queueing.
1356      */
1357     if (0 == ioctl (fd, SG_GET_VERSION_NUM, &sg_version))
1358       {
1359 	DBG (1, "sanei_scsi_open: SG driver version: %i\n", sg_version);
1360 
1361 	ioctl_val = ioctl (fd, SG_GET_SCSI_ID, &devinfo);
1362 	if (ioctl_val == EINVAL || ioctl_val == ENOTTY)
1363 	  {
1364 	    DBG (1, "sanei_scsi_open: The file %s is not an SG device file\n",
1365 		 dev);
1366 	    close (fd);
1367 	    return SANE_STATUS_INVAL;
1368 	  }
1369 
1370 	if (devinfo.scsi_type != 6 && devinfo.scsi_type != 3)
1371 	  {
1372 	    DBG (1,
1373 		 "sanei_scsi_open: The device found for %s does not look like a scanner\n",
1374 		 dev);
1375 	    close (fd);
1376 	    return SANE_STATUS_INVAL;
1377 	  }
1378 
1379 	/* try to reserve a SG buffer of the size specified by *buffersize
1380 	 */
1381 	ioctl (fd, SG_SET_RESERVED_SIZE, buffersize);
1382 
1383 	/* the set call may not be able to allocate as much memory
1384 	   as requested, thus we read the actual buffer size.
1385 	 */
1386 	if (0 == ioctl (fd, SG_GET_RESERVED_SIZE, &real_buffersize))
1387 	  {
1388 	    /* if we got more memory than requested, we stick with
1389 	       with the requested value, in order to allow
1390 	       sanei_scsi_open to check the buffer size exactly.
1391 	     */
1392 	    if (real_buffersize < *buffersize)
1393 	      *buffersize = real_buffersize;
1394 	    fdpa->buffersize = *buffersize;
1395 	  }
1396 	else
1397 	  {
1398 	    DBG (1, "sanei_scsi_open: cannot read SG buffer size - %s\n",
1399 		 strerror (errno));
1400 	    close (fd);
1401 	    return SANE_STATUS_NO_MEM;
1402 	  }
1403 	DBG (1, "sanei_scsi_open_extended: using %i bytes as SCSI buffer\n",
1404 	     *buffersize);
1405 
1406 	if (sg_version >= 20135)
1407 	  {
1408 	    DBG (1, "trying to enable low level command queueing\n");
1409 
1410 	    if (0 == ioctl (fd, SG_GET_SCSI_ID, &sid))
1411 	      {
1412 		DBG (1, "sanei_scsi_open: Host adapter queue depth: %i\n",
1413 		     sid.d_queue_depth);
1414 
1415 		ioctl_val = 1;
1416 		if (0 == ioctl (fd, SG_SET_COMMAND_Q, &ioctl_val))
1417 		  {
1418 		    fdpa->sg_queue_max = sid.d_queue_depth;
1419 		    if (fdpa->sg_queue_max <= 0)
1420 		      fdpa->sg_queue_max = 1;
1421 		  }
1422 	      }
1423 	  }
1424       }
1425     else
1426       {
1427 	/* we have a really old SG driver version, or we're not opening
1428 	   an SG device file
1429 	 */
1430 	if (ioctl (fd, SG_GET_TIMEOUT, &ioctl_val) < 0)
1431 	  {
1432 	    DBG (1, "sanei_scsi_open: The file %s is not an SG device file\n",
1433 		 dev);
1434 	    close (fd);
1435 	    return SANE_STATUS_INVAL;
1436 	  }
1437 	if (sanei_scsi_max_request_size < *buffersize)
1438 	  *buffersize = sanei_scsi_max_request_size;
1439 	fdpa->buffersize = *buffersize;
1440       }
1441     if (sg_version == 0)
1442       {
1443 	DBG (1, "sanei_scsi_open: using old SG driver logic\n");
1444       }
1445     else
1446       {
1447 	DBG (1,
1448 	     "sanei_scsi_open: SG driver can change buffer size at run time\n");
1449 	if (fdpa->sg_queue_max > 1)
1450 	  DBG (1, "sanei_scsi_open: low level command queueing enabled\n");
1451 #ifdef SG_IO
1452 	if (sg_version >= 30000)
1453 	  {
1454 	    DBG (1, "sanei_scsi_open: using new SG header structure\n");
1455 	  }
1456 #endif
1457       }
1458   }
1459 #endif /* LINUX_INTERFACE */
1460 #endif /* !DECUNIX_INTERFACE */
1461 
1462 /* Note: this really relies on fd to start small. Windows starts a little higher than 3. */
1463 
1464   if (fd >= num_alloced)
1465     {
1466       size_t new_size, old_size;
1467 
1468       old_size = num_alloced * sizeof (fd_info[0]);
1469       num_alloced = fd + 8;
1470       new_size = num_alloced * sizeof (fd_info[0]);
1471       if (fd_info)
1472 	fd_info = realloc (fd_info, new_size);
1473       else
1474 	fd_info = malloc (new_size);
1475       memset ((char *) fd_info + old_size, 0, new_size - old_size);
1476       if (!fd_info)
1477 	{
1478 	  if (!fake_fd)
1479 	    close (fd);
1480 	  return SANE_STATUS_NO_MEM;
1481 	}
1482     }
1483   fd_info[fd].in_use = 1;
1484   fd_info[fd].sense_handler = handler;
1485   fd_info[fd].sense_handler_arg = handler_arg;
1486   fd_info[fd].fake_fd = fake_fd;
1487   fd_info[fd].bus = bus;
1488   fd_info[fd].target = target;
1489   fd_info[fd].lun = lun;
1490   fd_info[fd].pdata = pdata;
1491 
1492 #if USE == SOLARIS_INTERFACE || USE == SOLARIS_USCSI_INTERFACE
1493   /* verify that the device really exists: */
1494   if (!unit_ready (fd))
1495     {
1496       sanei_scsi_close (fd);
1497       return SANE_STATUS_INVAL;
1498     }
1499 #endif
1500 #if USE == SYSVR4_INTERFACE
1501   memset (lastrcmd, 0, 16);	/* reinitialize last read command block */
1502 #endif
1503 
1504   if (fdp)
1505     *fdp = fd;
1506 
1507   return SANE_STATUS_GOOD;
1508 }
1509 
1510 #if USE == LINUX_INTERFACE
1511 /* The "wrapper" for the old open call */
1512 SANE_Status
sanei_scsi_open(const char * dev,int * fdp,SANEI_SCSI_Sense_Handler handler,void * handler_arg)1513 sanei_scsi_open (const char *dev, int *fdp,
1514 		 SANEI_SCSI_Sense_Handler handler, void *handler_arg)
1515 {
1516   int i = 0;
1517   int wanted_buffersize = SCSIBUFFERSIZE, real_buffersize;
1518   SANE_Status res;
1519   char *cc, *cc1;
1520   static int first_time = 1;
1521 
1522   if (first_time)
1523     {
1524       cc = getenv ("SANE_SG_BUFFERSIZE");
1525       if (cc)
1526 	{
1527 	  i = strtol (cc, &cc1, 10);
1528 	  if (cc != cc1 && i >= 32768)
1529 	    wanted_buffersize = i;
1530 	}
1531     }
1532   else
1533     wanted_buffersize = sanei_scsi_max_request_size;
1534 
1535   real_buffersize = wanted_buffersize;
1536   res = sanei_scsi_open_extended (dev, fdp, handler, handler_arg,
1537 				  &real_buffersize);
1538 
1539   /* make sure that we got as much memory as we wanted, otherwise
1540      the backend might be confused
1541    */
1542   if (!first_time && real_buffersize != wanted_buffersize)
1543     {
1544       DBG (1, "sanei_scsi_open: could not allocate SG buffer memory "
1545 	   "wanted: %i got: %i\n", wanted_buffersize, real_buffersize);
1546       sanei_scsi_close (*fdp);
1547       return SANE_STATUS_NO_MEM;
1548     }
1549 
1550   first_time = 0;
1551   return res;
1552 }
1553 #else
1554 /* dummy for the proposed new open call */
1555 SANE_Status
sanei_scsi_open_extended(const char * dev,int * fdp,SANEI_SCSI_Sense_Handler handler,void * handler_arg,int * buffersize)1556 sanei_scsi_open_extended (const char *dev, int *fdp,
1557 			  SANEI_SCSI_Sense_Handler handler,
1558 			  void *handler_arg, int *buffersize)
1559 {
1560   SANE_Status res;
1561   res = sanei_scsi_open (dev, fdp, handler, handler_arg);
1562   if (sanei_scsi_max_request_size < *buffersize)
1563     *buffersize = sanei_scsi_max_request_size;
1564   return res;
1565 }
1566 #endif
1567 
1568 void
sanei_scsi_close(int fd)1569 sanei_scsi_close (int fd)
1570 {
1571 #if USE == LINUX_INTERFACE
1572   if (fd_info[fd].pdata)
1573     {
1574       req *req, *next_req;
1575 
1576       /* make sure that there are no pending SCSI calls */
1577       sanei_scsi_req_flush_all_extended (fd);
1578 
1579       req = ((fdparms *) fd_info[fd].pdata)->sane_free_list;
1580       while (req)
1581 	{
1582 	  next_req = req->next;
1583 	  free (req);
1584 	  req = next_req;
1585 	}
1586       free (fd_info[fd].pdata);
1587     }
1588 #endif
1589 
1590   fd_info[fd].in_use = 0;
1591   fd_info[fd].sense_handler = 0;
1592   fd_info[fd].sense_handler_arg = 0;
1593 
1594 #ifdef WIN32
1595   CloseHandle(fd);
1596 #else
1597   if (!fd_info[fd].fake_fd)
1598     close (fd);
1599 #endif
1600 
1601 #if USE == FREEBSD_CAM_INTERFACE
1602   cam_close_device (cam_devices[fd]);
1603   cam_devices[fd] = NULL;
1604 #elif USE == DOMAINOS_INTERFACE
1605   {
1606     static int index;
1607     static status_$t status;
1608 
1609     DBG (1, "sanei_scsi_close:  fd=%d\n", fd);
1610 
1611     /* Send the command to the server */
1612     if (!mutex_$lock (&com->CommandLock, Wait16S))
1613       {
1614 	DBG (0, "Could not obtain mutex lock for Close command\n");
1615       }
1616     else
1617       {
1618 	com->opcode = Close;
1619 	com->fd = fd;
1620 	CommandTriggerValue[0] = ec2_$read (com->CommandAccepted) + 1;
1621 	ec2_$advance (&com->CommandAvailable, &status);
1622 	DomainErrorCheck (status, "Can't advance CommandAvailable EC");
1623 	CommandTriggerValue[1] = (ec2_$read (*CommandAcceptedPtr[1])
1624 				  + DomainECWaitConstant);
1625 	index = ec2_$wait_svc (CommandAcceptedPtr, CommandTriggerValue, 2,
1626 			       &status);
1627 	DomainErrorCheck (status,
1628 			  "Error waiting on Close command acceptance EC");
1629 	if (index != 1)
1630 	  {
1631 	    DBG (0, "Domain SANE Server never accepted Close Command\n");
1632 	  }
1633 
1634 	/* Read the result */
1635 	status = com->CommandStatus;
1636 	/* Release the lock */
1637 	mutex_$unlock (&com->CommandLock);
1638       }
1639 
1640     /* Unmap the data area */
1641     ms_$unmap (fd_info[com->fd].pdata, DomainMaxDataSize + DomainSenseSize,
1642 	       &status);
1643     DomainErrorCheck (status, "Error unmapping device data area");
1644   }
1645 #endif /* USE == DOMAINOS_INTERFACE */
1646 
1647 #if USE == OS2_INTERFACE
1648   close_aspi ();
1649 #endif /* USE == OS2_INTERFACE */
1650 
1651 #if USE == MACOSX_INTERFACE
1652   if (fd_info[fd].pdata)
1653     CFRelease (fd_info[fd].pdata);
1654 #endif /* USE == MACOSX_INTERFACE */
1655 }
1656 
1657 
1658 #if USE == DOMAINOS_INTERFACE
1659 # define WE_HAVE_ASYNC_SCSI
1660 
1661 void
sanei_scsi_req_flush_all(void)1662 sanei_scsi_req_flush_all (void)
1663 {
1664   status_$t status;
1665 
1666   DBG (1, "sanei_scsi_req_flush_all: ()\n");
1667   /* I have never seen this called, and I'm not sure what to do with it,
1668      so I guarantee that it will generate a fault, and I can add support
1669      for it.  */
1670   assert (1 == 0);
1671 }
1672 
1673 
1674 SANE_Status
sanei_scsi_req_enter2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size,void ** idp)1675 sanei_scsi_req_enter2 (int fd,
1676 		       const void *cmd, size_t cmd_size,
1677 		       const void *src, size_t src_size,
1678 		       void *dst, size_t * dst_size, void **idp)
1679 {
1680   SANEI_SCSI_Sense_Handler handler;
1681   static int index;
1682   static SANE_Status sane_status;
1683   static status_$t status;
1684   static scsi_$status_t SCSIStatus;
1685   static void *buf_ptr;
1686 
1687   if (dst_size)
1688     DBG (1, "sanei_scsi_req_enter2: (fd=%x, cmd=%p, cmd_size=%x, "
1689 	 "src=%p, src_size=%x, dst=%p, dst_size=%x, *idp=%p)\n",
1690 	 fd, cmd, cmd_size, src, src_size, dst, *dst_size, idp);
1691   else
1692     DBG (1, "sanei_scsi_req_enter2: (fd=%x, cmd=%p, cmd_size=%x, "
1693 	 "src=%p, src_size=%x, dst=%p, dst_size=NULL, *idp=%p)\n",
1694 	 fd, src, src_size, dst, idp);
1695 
1696   /* Lock the command structure */
1697   if (!mutex_$lock (&com->CommandLock, mutex_$wait_forever))
1698     {
1699       DBG (0, "Could not obtain mutex lock for Enter Command\n");
1700       return SANE_STATUS_INVAL;
1701     }
1702 
1703   /* Fill in the command structure */
1704   com->opcode = Enter;
1705   com->fd = fd;
1706   com->cdb_size = cmd_size;
1707   if (dst_size)
1708     com->dst_size = *dst_size;
1709   memcpy (&com->cdb, cmd, com->cdb_size);
1710 
1711   /* figure out if this is a read or a write */
1712   if (dst_size && *dst_size)
1713     {
1714       /* dest buffer specified, must be a read */
1715       /* assert (com->cdb_size == src_size); */
1716       com->direction = scsi_read;
1717       buf_ptr = dst;
1718       com->buf_size = *dst_size;
1719     }
1720   else
1721     {
1722       /* no dest buffer, must be a write */
1723       /* assert (com->cdb_size <= src_size); */
1724       com->direction = scsi_write;
1725       buf_ptr = (char *) src;
1726       com->buf_size = src_size;
1727       if (com->buf_size)
1728 	memcpy (fd_info[fd].pdata, buf_ptr, com->buf_size);
1729     }
1730 
1731   CommandTriggerValue[0] = ec2_$read (com->CommandAccepted) + 1;
1732   ec2_$advance (&com->CommandAvailable, &status);
1733   DomainErrorCheck (status, "Can't advance CommandAvailable EC");
1734   CommandTriggerValue[1] = (ec2_$read (*CommandAcceptedPtr[1])
1735 			    + DomainECWaitConstant);
1736   index = ec2_$wait_svc (CommandAcceptedPtr, CommandTriggerValue, 2, &status);
1737   DomainErrorCheck (status, "Error waiting on Enter command acceptance EC");
1738   if (index != 1)
1739     {
1740       DBG (0, "Domain SANE Server never accepted Enter Command\n");
1741       return SANE_STATUS_INVAL;
1742     }
1743 
1744   /* Read the result */
1745   status = com->CommandStatus;
1746   SCSIStatus = com->SCSIStatus;
1747 
1748   /* Release the lock */
1749   mutex_$unlock (&com->CommandLock);
1750 
1751   /* Now decode the return status */
1752   if (status.all)
1753     DBG (1, "Server returned status %08x from Enter command\n", status.all);
1754   switch (status.all)
1755     {
1756     case status_$ok:
1757       sane_status = SANE_STATUS_GOOD;
1758       break;
1759     case scsi_$dma_underrun:
1760       sane_status = SANE_STATUS_IO_ERROR;
1761       /* This error is generated by the HP and UMAX backends.  They
1762          ask for too much data.  For now, the error is ignored :-( */
1763       sane_status = SANE_STATUS_GOOD;
1764       break;
1765     case scsi_$operation_timeout:
1766       sane_status = SANE_STATUS_DEVICE_BUSY;
1767       break;
1768     case scsi_$hdwr_failure:	/* received when both scanners were active */
1769       sane_status = SANE_STATUS_IO_ERROR;
1770       break;
1771     case (status_$ok | 0x80000000):
1772       /* Special - no Domain/OS error, but fail bit set means to check
1773          SCSI operation status. */
1774       DBG (1, "Server returned SCSI status of %08x\n", SCSIStatus);
1775       switch (SCSIStatus)
1776 	{
1777 	case scsi_check_condition:
1778 	  /* Call the sense handler, if defined */
1779 	  handler = fd_info[com->fd].sense_handler;
1780 	  if (handler)
1781 	    (*handler) (fd, ((u_char *) fd_info[fd].pdata
1782 			     + DomainMaxDataSize),
1783 			fd_info[com->fd].sense_handler_arg);
1784 	  sane_status = SANE_STATUS_IO_ERROR;
1785 	  break;
1786 	case scsi_busy:
1787 	  sane_status = SANE_STATUS_DEVICE_BUSY;
1788 	  break;
1789 	default:
1790 	  DBG (0, "Error - Unrecognized SCSI status %08x returned from "
1791 	       "Enter command\n", SCSIStatus);
1792 	  sane_status = SANE_STATUS_IO_ERROR;
1793 	  exit (EXIT_FAILURE);
1794 	}
1795       break;
1796     default:
1797       DBG (0, "Unmapped status (%08x) returned from Domain SANE Server\n",
1798 	   status.all);
1799       sane_status = SANE_STATUS_IO_ERROR;
1800     }
1801 
1802   /* If a read, copy the data into the destination buffer */
1803   if ((com->direction == scsi_read) && com->dst_size)
1804     memcpy (buf_ptr, fd_info[fd].pdata, com->dst_size);
1805 
1806   return sane_status;
1807 }
1808 
1809 
1810 SANE_Status
sanei_scsi_req_wait(void * id)1811 sanei_scsi_req_wait (void *id)
1812 {
1813   SANE_Status status;
1814   DBG (1, "sanei_scsi_req_wait: (id=%p)\n", id);
1815   status = SANE_STATUS_GOOD;
1816   return status;
1817 }
1818 
1819 
1820 SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)1821 sanei_scsi_cmd2 (int fd,
1822 		 const void *cmd, size_t cmd_size,
1823 		 const void *src, size_t src_size,
1824 		 void *dst, size_t * dst_size)
1825 {
1826   SANE_Status status;
1827   void *id;
1828 
1829   DBG (1, "sanei_scsi_cmd2: (fd=%d)\n", fd);
1830   status =
1831     sanei_scsi_req_enter2 (fd, cmd, cmd_size, src, src_size, dst, dst_size,
1832 			   &id);
1833   if (status != SANE_STATUS_GOOD)
1834     return status;
1835   return sanei_scsi_req_wait (id);
1836 }
1837 
1838 #endif /* USE == DOMAINOS_INTERFACE */
1839 
1840 
1841 #if USE == LINUX_INTERFACE
1842 
1843 #include <ctype.h>
1844 #include <signal.h>
1845 
1846 #include <sys/time.h>
1847 
1848 #define WE_HAVE_ASYNC_SCSI
1849 #define WE_HAVE_FIND_DEVICES
1850 
1851 static int pack_id = 0;
1852 static int need_init = 1;
1853 static sigset_t all_signals;
1854 
1855 #define ATOMIC(s)					\
1856 do							\
1857   {							\
1858     sigset_t old_mask;					\
1859 							\
1860     if (need_init)					\
1861       {							\
1862 	need_init = 0;					\
1863 	sigfillset (&all_signals);			\
1864       }							\
1865     sigprocmask (SIG_BLOCK, &all_signals, &old_mask);	\
1866     {s;}						\
1867     sigprocmask (SIG_SETMASK, &old_mask, 0);		\
1868   }							\
1869 while (0)
1870 
1871 static void
issue(struct req * req)1872 issue (struct req *req)
1873 {
1874   ssize_t nwritten;
1875   fdparms *fdp;
1876   struct req *rp;
1877   int retries;
1878   int ret;
1879 
1880   if (!req)
1881     return;
1882 
1883   fdp = (fdparms *) fd_info[req->fd].pdata;
1884   DBG (4, "sanei_scsi.issue: %p\n", (void *) req);
1885 
1886   rp = fdp->sane_qhead;
1887   while (rp && rp->running)
1888     rp = rp->next;
1889 
1890   while (rp && fdp->sg_queue_used < fdp->sg_queue_max)
1891     {
1892       retries = 20;
1893       while (retries)
1894 	{
1895 	  errno = 0;
1896 #ifdef SG_IO
1897 	  if (sg_version < 30000)
1898 	    {
1899 #endif
1900 	      ATOMIC (rp->running = 1;
1901 		      nwritten = write (rp->fd, &rp->sgdata.cdb,
1902 					rp->sgdata.cdb.hdr.pack_len);
1903 		      ret = 0;
1904 		      if (nwritten != rp->sgdata.cdb.hdr.pack_len)
1905 		      {
1906 		      /* ENOMEM can easily happen, if both command queueing
1907 		         inside the SG driver and large buffers are used.
1908 		         Therefore, if ENOMEM does not occur for the first
1909 		         command in the queue, we simply try to issue
1910 		         it later again.
1911 		       */
1912 		      if (errno == EAGAIN
1913 			  || (errno == ENOMEM && rp != fdp->sane_qhead))
1914 		      {
1915 		      /* don't try to send the data again, but
1916 		         wait for the next call to issue()
1917 		       */
1918 		      rp->running = 0;}
1919 		      }
1920 	      );
1921 #ifdef SG_IO
1922 	    }
1923 	  else
1924 	    {
1925 	      ATOMIC (rp->running = 1;
1926 		      ret = ioctl(rp->fd, SG_IO, &rp->sgdata.sg3.hdr);
1927 		      nwritten = 0;
1928 		      if (ret < 0)
1929 		      {
1930 		      /* ENOMEM can easily happen, if both command queuein
1931 		         inside the SG driver and large buffers are used.
1932 		         Therefore, if ENOMEM does not occur for the first
1933 		         command in the queue, we simply try to issue
1934 		         it later again.
1935 		       */
1936 			if (errno == EAGAIN
1937 			    || (errno == ENOMEM && rp != fdp->sane_qhead))
1938 			  {
1939 			    /* don't try to send the data again, but
1940 			       wait for the next call to issue()
1941 			    */
1942 			    rp->running = 0;
1943 			  }
1944 			else /* game over */
1945 			  {
1946 			    rp->running = 0;
1947 			    rp->done = 1;
1948 			    rp->status = SANE_STATUS_IO_ERROR;
1949 			  }
1950 		      }
1951 	      );
1952 	      IF_DBG (if (DBG_LEVEL >= 255)
1953 		      system ("cat /proc/scsi/sg/debug 1>&2");)
1954 		}
1955 #endif
1956 		if (rp == fdp->sane_qhead && errno == EAGAIN)
1957 		  {
1958 		    retries--;
1959 		    usleep (10000);
1960 		  }
1961 		else
1962 		  retries = 0;
1963 	    }
1964 
1965 #ifndef SG_IO
1966 	  if (nwritten != rp->sgdata.cdb.hdr.pack_len)
1967 #else
1968 	  if ((sg_version < 30000 && nwritten != rp->sgdata.cdb.hdr.pack_len)
1969 	      || (sg_version >= 30000 && ret < 0))
1970 #endif
1971 	    {
1972 	      if (rp->running)
1973 		{
1974 #ifdef SG_IO
1975 		  if (sg_version < 30000)
1976 #endif
1977 		    DBG (1, "sanei_scsi.issue: bad write (errno=%i) %s %li\n",
1978 			 errno, strerror (errno), (long)nwritten);
1979 #ifdef SG_IO
1980 		  else if (sg_version > 30000)
1981 		    DBG (1, "sanei_scsi.issue: SG_IO ioctl error (errno=%i, ret=%d) %s\n",
1982 			 errno, ret, strerror (errno));
1983 #endif
1984 		  rp->done = 1;
1985 		  if (errno == ENOMEM)
1986 		    {
1987 		      DBG (1, "sanei_scsi.issue: SG_BIG_BUF inconsistency? "
1988 			   "Check file PROBLEMS.\n");
1989 		      rp->status = SANE_STATUS_NO_MEM;
1990 		    }
1991 		  else
1992 		    rp->status = SANE_STATUS_IO_ERROR;
1993 		}
1994 	      else
1995 		{
1996 		  if (errno == ENOMEM)
1997 		    DBG (1, "issue: ENOMEM - cannot queue SCSI command. "
1998 			 "Trying again later.\n");
1999 		  else
2000 		    DBG (1, "issue: EAGAIN - cannot queue SCSI command. "
2001 			 "Trying again later.\n");
2002 		}
2003 	      break;		/* in case of an error don't try to queue more commands */
2004 	    }
2005 	  else
2006 	    {
2007 #ifdef SG_IO
2008 	      if (sg_version < 30000)
2009 #endif
2010 		req->status = SANE_STATUS_IO_ERROR;
2011 #ifdef SG_IO
2012 	      else if (sg_version > 30000) /* SG_IO is synchronous, we're all set */
2013 		req->status = SANE_STATUS_GOOD;
2014 #endif
2015 	    }
2016 	  fdp->sg_queue_used++;
2017 	  rp = rp->next;
2018     }
2019 }
2020 
sanei_scsi_req_flush_all_extended(int fd)2021   void sanei_scsi_req_flush_all_extended (int fd)
2022   {
2023     fdparms *fdp;
2024     struct req *req, *next_req;
2025     int len, count;
2026 
2027     fdp = (fdparms *) fd_info[fd].pdata;
2028     for (req = fdp->sane_qhead; req; req = next_req)
2029       {
2030 	if (req->running && !req->done)
2031 	  {
2032 	    count = sane_scsicmd_timeout * 10;
2033 	    while (count)
2034 	      {
2035 		errno = 0;
2036 #ifdef SG_IO
2037 		if (sg_version < 30000)
2038 #endif
2039 		  len =
2040 		    read (fd, &req->sgdata.cdb,
2041 			  req->sgdata.cdb.hdr.reply_len);
2042 #ifdef SG_IO
2043 		else
2044 		  len = read (fd, &req->sgdata.sg3.hdr, sizeof (Sg_io_hdr));
2045 #endif
2046 		if (len >= 0 || (len < 0 && errno != EAGAIN))
2047 		  break;
2048 		usleep (100000);
2049 		count--;
2050 	      }
2051 	    ((fdparms *) fd_info[req->fd].pdata)->sg_queue_used--;
2052 	  }
2053 	next_req = req->next;
2054 
2055 	req->next = fdp->sane_free_list;
2056 	fdp->sane_free_list = req;
2057       }
2058 
2059     fdp->sane_qhead = fdp->sane_qtail = 0;
2060   }
2061 
sanei_scsi_req_flush_all()2062   void sanei_scsi_req_flush_all ()
2063   {
2064     int fd, i, j = 0;
2065 
2066     /* sanei_scsi_open allows only one open file handle, so we
2067        can simply look for the first entry where in_use is set
2068      */
2069 
2070     fd = num_alloced;
2071     for (i = 0; i < num_alloced; i++)
2072       if (fd_info[i].in_use)
2073 	{
2074 	  j++;
2075 	  fd = i;
2076 	}
2077 
2078     assert (j < 2);
2079 
2080     if (fd < num_alloced)
2081       sanei_scsi_req_flush_all_extended (fd);
2082   }
2083 
2084   SANE_Status
sanei_scsi_req_enter2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size,void ** idp)2085     sanei_scsi_req_enter2 (int fd,
2086 			   const void *cmd, size_t cmd_size,
2087 			   const void *src, size_t src_size,
2088 			   void *dst, size_t * dst_size, void **idp)
2089   {
2090     struct req *req;
2091     size_t size;
2092     fdparms *fdp;
2093 
2094     fdp = (fdparms *) fd_info[fd].pdata;
2095 
2096     if (fdp->sane_free_list)
2097       {
2098 	req = fdp->sane_free_list;
2099 	fdp->sane_free_list = req->next;
2100 	req->next = 0;
2101       }
2102     else
2103       {
2104 #ifdef SG_IO
2105 	if (sg_version < 30000)
2106 #endif
2107 	  size = (sizeof (*req) - sizeof (req->sgdata.cdb.data)
2108 		  + fdp->buffersize);
2109 #ifdef SG_IO
2110 	else
2111 	  size = sizeof (*req) + MAX_CDB + fdp->buffersize
2112 	    - sizeof (req->sgdata.sg3.data);
2113 #endif
2114 	req = malloc (size);
2115 	if (!req)
2116 	  {
2117 	    DBG (1, "sanei_scsi_req_enter: failed to malloc %lu bytes\n",
2118 		 (u_long) size);
2119 	    return SANE_STATUS_NO_MEM;
2120 	  }
2121       }
2122     req->fd = fd;
2123     req->running = 0;
2124     req->done = 0;
2125     req->status = SANE_STATUS_GOOD;
2126     req->dst = dst;
2127     req->dst_len = dst_size;
2128 #ifdef SG_IO
2129     if (sg_version < 30000)
2130       {
2131 #endif
2132 	memset (&req->sgdata.cdb.hdr, 0, sizeof (req->sgdata.cdb.hdr));
2133 	req->sgdata.cdb.hdr.pack_id = pack_id++;
2134 	req->sgdata.cdb.hdr.pack_len = cmd_size + src_size
2135 	  + sizeof (req->sgdata.cdb.hdr);
2136 	req->sgdata.cdb.hdr.reply_len = (dst_size ? *dst_size : 0)
2137 	  + sizeof (req->sgdata.cdb.hdr);
2138 	memcpy (&req->sgdata.cdb.data, cmd, cmd_size);
2139 	memcpy (&req->sgdata.cdb.data[cmd_size], src, src_size);
2140 	if (CDB_SIZE (*(const u_char *) cmd) != cmd_size)
2141 	  {
2142 	    if (ioctl (fd, SG_NEXT_CMD_LEN, &cmd_size))
2143 	      {
2144 		DBG (1,
2145 		     "sanei_scsi_req_enter2: ioctl to set command length failed\n");
2146 	      }
2147 	  }
2148 #ifdef SG_IO
2149       }
2150     else
2151       {
2152 	memset (&req->sgdata.sg3.hdr, 0, sizeof (req->sgdata.sg3.hdr));
2153 	req->sgdata.sg3.hdr.interface_id = 'S';
2154 	req->sgdata.sg3.hdr.cmd_len = cmd_size;
2155 	req->sgdata.sg3.hdr.iovec_count = 0;
2156 	req->sgdata.sg3.hdr.mx_sb_len = SENSE_MAX;
2157 	/* read or write? */
2158 	if (dst_size && *dst_size)
2159 	  {
2160 	    req->sgdata.sg3.hdr.dxfer_direction = SG_DXFER_FROM_DEV;
2161 	    req->sgdata.sg3.hdr.dxfer_len = *dst_size;
2162 	    req->sgdata.sg3.hdr.dxferp = dst;
2163 	  }
2164 	else if (src_size)
2165 	  {
2166 	    req->sgdata.sg3.hdr.dxfer_direction = SG_DXFER_TO_DEV;
2167 	    if (src_size > fdp->buffersize)
2168 	      {
2169 		DBG (1,
2170 		     "sanei_scsi_req_enter2 warning: truncating write data "
2171 		     "from requested %li bytes to allowed %li bytes\n",
2172 		     (long)src_size, (long)fdp->buffersize);
2173 		src_size = fdp->buffersize;
2174 	      }
2175 	    req->sgdata.sg3.hdr.dxfer_len = src_size;
2176 	    memcpy (&req->sgdata.sg3.data[MAX_CDB], src, src_size);
2177 	    req->sgdata.sg3.hdr.dxferp = &req->sgdata.sg3.data[MAX_CDB];
2178 	  }
2179 	else
2180 	  {
2181 	    req->sgdata.sg3.hdr.dxfer_direction = SG_DXFER_NONE;
2182 	  }
2183 	if (cmd_size > MAX_CDB)
2184 	  {
2185 	    DBG (1, "sanei_scsi_req_enter2 warning: truncating write data "
2186 		 "from requested %li bytes to allowed %i bytes\n",
2187 		 (long)cmd_size, MAX_CDB);
2188 	    cmd_size = MAX_CDB;
2189 	  }
2190 	memcpy (req->sgdata.sg3.data, cmd, cmd_size);
2191 	req->sgdata.sg3.hdr.cmdp = req->sgdata.sg3.data;
2192 	req->sgdata.sg3.hdr.sbp = &(req->sgdata.sg3.sense_buffer[0]);
2193 	req->sgdata.sg3.hdr.timeout = 1000 * sane_scsicmd_timeout;
2194 #ifdef ENABLE_SCSI_DIRECTIO
2195 	/* for the adventurous: If direct IO is used,
2196 	   the kernel locks the buffer. This can lead to conflicts,
2197 	   if a backend uses shared memory.
2198 	   OTOH, direct IO may be faster, and it reduces memory usage
2199 	 */
2200 	req->sgdata.sg3.hdr.flags = SG_FLAG_DIRECT_IO;
2201 #else
2202 	req->sgdata.sg3.hdr.flags = 0;
2203 #endif
2204 	req->sgdata.sg3.hdr.pack_id = pack_id++;
2205 	req->sgdata.sg3.hdr.usr_ptr = 0;
2206       }
2207 #endif
2208 
2209     req->next = 0;
2210     ATOMIC (if (fdp->sane_qtail)
2211 	    {
2212 	    fdp->sane_qtail->next = req; fdp->sane_qtail = req;}
2213 	    else
2214 	    fdp->sane_qhead = fdp->sane_qtail = req);
2215 
2216     DBG (4, "scsi_req_enter: entered %p\n", (void *) req);
2217 
2218     *idp = req;
2219     issue (req);
2220 
2221     DBG (10, "scsi_req_enter: queue_used: %i, queue_max: %i\n",
2222 	 ((fdparms *) fd_info[fd].pdata)->sg_queue_used,
2223 	 ((fdparms *) fd_info[fd].pdata)->sg_queue_max);
2224 
2225     return SANE_STATUS_GOOD;
2226   }
2227 
sanei_scsi_req_wait(void * id)2228   SANE_Status sanei_scsi_req_wait (void *id)
2229   {
2230     SANE_Status status = SANE_STATUS_GOOD;
2231     struct req *req = id;
2232     ssize_t nread = 0;
2233 
2234     /* we don't support out-of-order completion */
2235     assert (req == ((fdparms *) fd_info[req->fd].pdata)->sane_qhead);
2236 
2237     DBG (4, "sanei_scsi_req_wait: waiting for %p\n", (void *) req);
2238 
2239     issue (req);		/* ensure the command is running */
2240     if (req->done)
2241       {
2242 	issue (req->next);	/* issue next command, if any */
2243 	status = req->status;
2244       }
2245     else
2246       {
2247 #ifdef SG_IO
2248 	if (sg_version < 30000)
2249 	  {
2250 #endif
2251 	    fd_set readable;
2252 
2253 	    /* wait for command completion: */
2254 	    FD_ZERO (&readable);
2255 	    FD_SET (req->fd, &readable);
2256 	    select (req->fd + 1, &readable, 0, 0, 0);
2257 
2258 	    /* now atomically read result and set DONE: */
2259 	    ATOMIC (nread = read (req->fd, &req->sgdata.cdb,
2260 				  req->sgdata.cdb.hdr.reply_len);
2261 		    req->done = 1);
2262 #ifdef SG_IO
2263 	  }
2264 	else
2265 	  {
2266 	    IF_DBG (if (DBG_LEVEL >= 255)
2267 		    system ("cat /proc/scsi/sg/debug 1>&2");)
2268 
2269 	      /* set DONE: */
2270 	      nread = 0; /* unused in this code path */
2271 	      req->done = 1;
2272 	  }
2273 #endif
2274 
2275 	if (fd_info[req->fd].pdata)
2276 	  ((fdparms *) fd_info[req->fd].pdata)->sg_queue_used--;
2277 
2278 	/* Now issue next command asap, if any.  We can't do this
2279 	   earlier since the Linux kernel has space for just one big
2280 	   buffer.  */
2281 	issue (req->next);
2282 
2283 	DBG (4, "sanei_scsi_req_wait: read %ld bytes\n", (long) nread);
2284 
2285 	if (nread < 0)
2286 	  {
2287 	    DBG (1, "sanei_scsi_req_wait: read returned %ld (errno=%d)\n",
2288 		 (long) nread, errno);
2289 	    status = SANE_STATUS_IO_ERROR;
2290 	  }
2291 	else
2292 	  {
2293 #ifdef SG_IO
2294 	    if (sg_version < 30000)
2295 	      {
2296 #endif
2297 		nread -= sizeof (req->sgdata.cdb.hdr);
2298 
2299 		/* check for errors, but let the sense_handler decide.... */
2300 		if ((req->sgdata.cdb.hdr.result != 0) ||
2301 		    (((req->sgdata.cdb.hdr.sense_buffer[0] & 0x7f) != 0)
2302 #ifdef HAVE_SG_TARGET_STATUS
2303 		     /* this is messy... Sometimes it happens that we have
2304 		        a valid looking sense buffer, but the DRIVER_SENSE
2305 		        bit is not set. Moreover, we can check this only for
2306 		        not too old SG drivers
2307 		      */
2308 		     && (req->sgdata.cdb.hdr.driver_status & DRIVER_SENSE)
2309 #endif
2310 		    ))
2311 		  {
2312 		    SANEI_SCSI_Sense_Handler handler
2313 		      = fd_info[req->fd].sense_handler;
2314 		    void *arg = fd_info[req->fd].sense_handler_arg;
2315 
2316 		    DBG (1,
2317 			 "sanei_scsi_req_wait: SCSI command complained: %s\n",
2318 			 strerror (req->sgdata.cdb.hdr.result));
2319 		    DBG (10,
2320 			 "sense buffer: %02x %02x %02x %02x %02x %02x %02x %02x"
2321 			 " %02x %02x %02x %02x %02x %02x %02x %02x\n",
2322 			 req->sgdata.cdb.hdr.sense_buffer[0],
2323 			 req->sgdata.cdb.hdr.sense_buffer[1],
2324 			 req->sgdata.cdb.hdr.sense_buffer[2],
2325 			 req->sgdata.cdb.hdr.sense_buffer[3],
2326 			 req->sgdata.cdb.hdr.sense_buffer[4],
2327 			 req->sgdata.cdb.hdr.sense_buffer[5],
2328 			 req->sgdata.cdb.hdr.sense_buffer[6],
2329 			 req->sgdata.cdb.hdr.sense_buffer[7],
2330 			 req->sgdata.cdb.hdr.sense_buffer[8],
2331 			 req->sgdata.cdb.hdr.sense_buffer[9],
2332 			 req->sgdata.cdb.hdr.sense_buffer[10],
2333 			 req->sgdata.cdb.hdr.sense_buffer[11],
2334 			 req->sgdata.cdb.hdr.sense_buffer[12],
2335 			 req->sgdata.cdb.hdr.sense_buffer[13],
2336 			 req->sgdata.cdb.hdr.sense_buffer[14],
2337 			 req->sgdata.cdb.hdr.sense_buffer[15]);
2338 #ifdef HAVE_SG_TARGET_STATUS
2339 		    /* really old SG header do not define target_status,
2340 		       host_status and driver_status
2341 		     */
2342 		    DBG (10, "target status: %02x host status: %02x"
2343 			 " driver status: %02x\n",
2344 			 req->sgdata.cdb.hdr.target_status,
2345 			 req->sgdata.cdb.hdr.host_status,
2346 			 req->sgdata.cdb.hdr.driver_status);
2347 
2348 		    if (req->sgdata.cdb.hdr.host_status == DID_NO_CONNECT || req->sgdata.cdb.hdr.host_status == DID_BUS_BUSY || req->sgdata.cdb.hdr.host_status == DID_TIME_OUT || req->sgdata.cdb.hdr.driver_status == DRIVER_BUSY || req->sgdata.cdb.hdr.target_status == 0x04)	/* BUSY */
2349 #else
2350 		    if (req->sgdata.cdb.hdr.result == EBUSY)
2351 #endif
2352 		      status = SANE_STATUS_DEVICE_BUSY;
2353 		    else if (handler)
2354 		      /* sense handler should return SANE_STATUS_GOOD if it
2355 		         decided all was ok after all */
2356 		      status =
2357 			(*handler) (req->fd, req->sgdata.cdb.hdr.sense_buffer,
2358 				    arg);
2359 		    else
2360 		      status = SANE_STATUS_IO_ERROR;
2361 		  }
2362 
2363 		/* if we are ok so far, copy over the return data */
2364 		if (status == SANE_STATUS_GOOD)
2365 		  {
2366 		    if (req->dst)
2367 		      memcpy (req->dst, req->sgdata.cdb.data, nread);
2368 
2369 		    if (req->dst_len)
2370 		      *req->dst_len = nread;
2371 		  }
2372 #ifdef SG_IO
2373 	      }
2374 	    else
2375 	      {
2376 		/* check for errors, but let the sense_handler decide.... */
2377 		if (((req->sgdata.sg3.hdr.info & SG_INFO_CHECK) != 0)
2378 		    || ((req->sgdata.sg3.hdr.sb_len_wr > 0)
2379 			&& ((req->sgdata.sg3.sense_buffer[0] & 0x7f) != 0)
2380 			&& (req->sgdata.sg3.hdr.
2381 			    driver_status & DRIVER_SENSE)))
2382 		  {
2383 		    SANEI_SCSI_Sense_Handler handler
2384 		      = fd_info[req->fd].sense_handler;
2385 		    void *arg = fd_info[req->fd].sense_handler_arg;
2386 
2387 		    DBG (1,
2388 			 "sanei_scsi_req_wait: SCSI command complained: %s\n",
2389 			 strerror (errno));
2390 		    DBG (10,
2391 			 "sense buffer: %02x %02x %02x %02x %02x %02x %02x %02x"
2392 			 " %02x %02x %02x %02x %02x %02x %02x %02x\n",
2393 			 req->sgdata.sg3.sense_buffer[0],
2394 			 req->sgdata.sg3.sense_buffer[1],
2395 			 req->sgdata.sg3.sense_buffer[2],
2396 			 req->sgdata.sg3.sense_buffer[3],
2397 			 req->sgdata.sg3.sense_buffer[4],
2398 			 req->sgdata.sg3.sense_buffer[5],
2399 			 req->sgdata.sg3.sense_buffer[6],
2400 			 req->sgdata.sg3.sense_buffer[7],
2401 			 req->sgdata.sg3.sense_buffer[8],
2402 			 req->sgdata.sg3.sense_buffer[9],
2403 			 req->sgdata.sg3.sense_buffer[10],
2404 			 req->sgdata.sg3.sense_buffer[11],
2405 			 req->sgdata.sg3.sense_buffer[12],
2406 			 req->sgdata.sg3.sense_buffer[13],
2407 			 req->sgdata.sg3.sense_buffer[14],
2408 			 req->sgdata.sg3.sense_buffer[15]);
2409 		    DBG (10,
2410 			 "target status: %02x host status: %04x"
2411 			 " driver status: %04x\n", req->sgdata.sg3.hdr.status,
2412 			 req->sgdata.sg3.hdr.host_status,
2413 			 req->sgdata.sg3.hdr.driver_status);
2414 
2415 		    /* the first three tests below are an replacement of the
2416 		       error "classification" as it was with the old SG driver,
2417 		       the fourth test is new.
2418 		     */
2419 		    if (req->sgdata.sg3.hdr.host_status == SG_ERR_DID_NO_CONNECT || req->sgdata.sg3.hdr.host_status == SG_ERR_DID_BUS_BUSY || req->sgdata.sg3.hdr.host_status == SG_ERR_DID_TIME_OUT || req->sgdata.sg3.hdr.driver_status == DRIVER_BUSY || req->sgdata.sg3.hdr.masked_status == 0x04)	/* BUSY */
2420 		      status = SANE_STATUS_DEVICE_BUSY;
2421 		    else if (handler && req->sgdata.sg3.hdr.sb_len_wr)
2422 		      /* sense handler should return SANE_STATUS_GOOD if it
2423 		         decided all was ok after all */
2424 		      status =
2425 			(*handler) (req->fd, req->sgdata.sg3.sense_buffer,
2426 				    arg);
2427 
2428 		    /* status bits INTERMEDIATE and CONDITION MET should not
2429 		       result in an error; neither should reserved bits
2430 		     */
2431 		    else if (((req->sgdata.sg3.hdr.status & 0x2a) == 0)
2432 			     && (req->sgdata.sg3.hdr.host_status ==
2433 				 SG_ERR_DID_OK)
2434 			     &&
2435 			     ((req->sgdata.sg3.hdr.
2436 			       driver_status & ~SG_ERR_DRIVER_SENSE) ==
2437 			      SG_ERR_DRIVER_OK))
2438 		      status = SANE_STATUS_GOOD;
2439 		    else
2440 		      status = SANE_STATUS_IO_ERROR;
2441 		  }
2442 
2443 #if 0
2444 		/* Sometimes the Linux SCSI system reports bogus resid values.
2445 		   Observed with lk 2.4.5, 2.4.13, aic7xxx and sym53c8xx drivers,
2446 		   if command queueing is used. So we better issue only a warning
2447 		 */
2448 		if (status == SANE_STATUS_GOOD)
2449 		  {
2450 		    if (req->dst_len)
2451 		      {
2452 			*req->dst_len -= req->sgdata.sg3.hdr.resid;
2453 		      }
2454 		  }
2455 #endif
2456 		if (req->sgdata.sg3.hdr.resid)
2457 		  {
2458 		    DBG (1,
2459 			 "sanei_scsi_req_wait: SG driver returned resid %i\n",
2460 			 req->sgdata.sg3.hdr.resid);
2461 		    DBG (1,
2462 			 "                     NOTE: This value may be bogus\n");
2463 		  }
2464 	      }
2465 #endif
2466 	  }
2467       }
2468 
2469     /* dequeue and release processed request: */
2470     ATOMIC (((fdparms *) fd_info[req->fd].pdata)->sane_qhead
2471 	    = ((fdparms *) fd_info[req->fd].pdata)->sane_qhead->next;
2472 	    if (!((fdparms *) fd_info[req->fd].pdata)->sane_qhead)
2473 	    ((fdparms *) fd_info[req->fd].pdata)->sane_qtail = 0;
2474 	    req->next = ((fdparms *) fd_info[req->fd].pdata)->sane_free_list;
2475 	    ((fdparms *) fd_info[req->fd].pdata)->sane_free_list = req);
2476     return status;
2477   }
2478 
2479   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)2480     sanei_scsi_cmd2 (int fd,
2481 		     const void *cmd, size_t cmd_size,
2482 		     const void *src, size_t src_size,
2483 		     void *dst, size_t * dst_size)
2484   {
2485     SANE_Status status;
2486     void *id;
2487 
2488     status =
2489       sanei_scsi_req_enter2 (fd, cmd, cmd_size, src, src_size, dst, dst_size,
2490 			     &id);
2491     if (status != SANE_STATUS_GOOD)
2492       return status;
2493     return sanei_scsi_req_wait (id);
2494   }
2495 
2496 /* The following code (up to and including sanei_scsi_find_devices() )
2497    is trying to match device/manufacturer names and/or SCSI addressing
2498    numbers (i.e. <host,bus,id,lun>) with a sg device file name
2499    (e.g. /dev/sg3).
2500 */
2501 #define PROCFILE	"/proc/scsi/scsi"
2502 #define DEVFS_MSK	"/dev/scsi/host%d/bus%d/target%d/lun%d/generic"
2503 #define SCAN_MISSES 5
2504 
2505 /* Some <scsi/scsi.h> headers don't have the following define */
2506 #ifndef SCSI_IOCTL_GET_IDLUN
2507 #define SCSI_IOCTL_GET_IDLUN 0x5382
2508 #endif
2509 
2510   static int lx_sg_dev_base = -1;
2511   static int lx_devfs = -1;
2512 
2513   static const struct lx_device_name_list_tag
2514   {
2515     const char *prefix;
2516     char base;
2517   }
2518   lx_dnl[] =
2519   {
2520     {
2521     "/dev/sg", 0}
2522     ,
2523     {
2524     "/dev/sg", 'a'}
2525     ,
2526     {
2527     "/dev/uk", 0}
2528     ,
2529     {
2530     "/dev/gsc", 0}
2531   };
2532 
2533   static int			/* Returns open sg file descriptor, or -1 for no access,
2534 				   or -2 for not found (or other error) */
lx_mk_devicename(int guess_devnum,char * name,size_t name_len)2535     lx_mk_devicename (int guess_devnum, char *name, size_t name_len)
2536   {
2537     int dev_fd, k, dnl_len;
2538     const struct lx_device_name_list_tag *dnp;
2539 
2540     dnl_len = NELEMS (lx_dnl);
2541     k = ((-1 == lx_sg_dev_base) ? 0 : lx_sg_dev_base);
2542     for (; k < dnl_len; ++k)
2543       {
2544 	dnp = &lx_dnl[k];
2545 	if (dnp->base)
2546 	  snprintf (name, name_len, "%s%c", dnp->prefix,
2547 		    dnp->base + guess_devnum);
2548 	else
2549 	  snprintf (name, name_len, "%s%d", dnp->prefix, guess_devnum);
2550    dev_fd = -1;
2551 #ifdef HAVE_RESMGR
2552    dev_fd = rsm_open_device (name, O_RDWR | O_NONBLOCK);
2553 #endif
2554    if (dev_fd == -1)
2555      dev_fd = open (name, O_RDWR | O_NONBLOCK);
2556 	if (dev_fd >= 0)
2557 	  {
2558 	    lx_sg_dev_base = k;
2559 	    return dev_fd;
2560 	  }
2561 	else if ((EACCES == errno) || (EBUSY == errno))
2562 	  {
2563 	    lx_sg_dev_base = k;
2564 	    return -1;
2565 	  }
2566 	if (-1 != lx_sg_dev_base)
2567 	  return -2;
2568       }
2569     return -2;
2570   }
2571 
2572   static int			/* Returns 1 for match, else 0 */
lx_chk_id(int dev_fd,int host,int channel,int id,int lun)2573     lx_chk_id (int dev_fd, int host, int channel, int id, int lun)
2574   {
2575 #ifdef SG_GET_SCSI_ID_FOUND
2576     struct sg_scsi_id ssid;
2577 
2578     if ((ioctl (dev_fd, SG_GET_SCSI_ID, &ssid) >= 0))
2579       {
2580 	DBG (2, "lx_chk_id: %d,%d  %d,%d  %d,%d  %d,%d\n", host, ssid.host_no,
2581 	     channel, ssid.channel, id, ssid.scsi_id, lun, ssid.lun);
2582 	if ((host == ssid.host_no) &&
2583 	    (channel == ssid.channel) &&
2584 	    (id == ssid.scsi_id) && (lun == ssid.lun))
2585 	  return 1;
2586 	else
2587 	  return 0;
2588       }
2589 #endif
2590     {
2591       struct my_scsi_idlun
2592       {
2593 	int dev_id;
2594 	int host_unique_id;
2595       }
2596       my_idlun;
2597       if (ioctl (dev_fd, SCSI_IOCTL_GET_IDLUN, &my_idlun) >= 0)
2598 	{
2599 	  if (((my_idlun.dev_id & 0xff) == id) &&
2600 	      (((my_idlun.dev_id >> 8) & 0xff) == lun) &&
2601 	      (((my_idlun.dev_id >> 16) & 0xff) == channel))
2602 	    return 1;		/* cheating, assume 'host' number matches */
2603 	}
2604     }
2605     return 0;
2606   }
2607 
2608   static int			/* Returns 1 if match with 'name' set, else 0 */
2609 
lx_scan_sg(int exclude_devnum,char * name,size_t name_len,int host,int channel,int id,int lun)2610     lx_scan_sg (int exclude_devnum, char *name, size_t name_len,
2611 		int host, int channel, int id, int lun)
2612   {
2613     int dev_fd, k, missed;
2614 
2615     if (-1 == lx_sg_dev_base)
2616       return 0;
2617     for (k = 0, missed = 0; (missed < SCAN_MISSES) && (k < 255);
2618 	 ++k, ++missed)
2619       {
2620 	DBG (2, "lx_scan_sg: k=%d, exclude=%d, missed=%d\n", k,
2621 	     exclude_devnum, missed);
2622 	if (k == exclude_devnum)
2623 	  {
2624 	    missed = 0;
2625 	    continue;		/* assumed this one has been checked already */
2626 	  }
2627 	if ((dev_fd = lx_mk_devicename (k, name, name_len)) >= 0)
2628 	  {
2629 	    missed = 0;
2630 	    if (lx_chk_id (dev_fd, host, channel, id, lun))
2631 	      {
2632 		close (dev_fd);
2633 		return 1;
2634 	      }
2635 	    close (dev_fd);
2636 	  }
2637 	else if (-1 == dev_fd)
2638 	  missed = 0;		/* no permissions but something found */
2639       }
2640     return 0;
2641   }
2642 
2643   static int			/* Returns 1 if match, else 0 */
2644 
lx_chk_devicename(int guess_devnum,char * name,size_t name_len,int host,int channel,int id,int lun)2645     lx_chk_devicename (int guess_devnum, char *name, size_t name_len,
2646 		       int host, int channel, int id, int lun)
2647   {
2648     int dev_fd;
2649 
2650     if (host < 0)
2651       return 0;
2652     if (0 != lx_devfs)
2653       {				/* simple mapping if we have devfs */
2654 	if (-1 == lx_devfs)
2655 	  {
2656 	    if ((dev_fd =
2657 		 lx_mk_devicename (guess_devnum, name, name_len)) >= 0)
2658 	      close (dev_fd);	/* hack to load sg driver module */
2659 	  }
2660 	snprintf (name, name_len, DEVFS_MSK, host, channel, id, lun);
2661 	dev_fd = open (name, O_RDWR | O_NONBLOCK);
2662 	if (dev_fd >= 0)
2663 	  {
2664 	    close (dev_fd);
2665 	    lx_devfs = 1;
2666 	    DBG (1, "lx_chk_devicename: matched device(devfs): %s\n", name);
2667 	    return 1;
2668 	  }
2669 	else if (ENOENT == errno)
2670 	  lx_devfs = 0;
2671       }
2672 
2673     if ((dev_fd = lx_mk_devicename (guess_devnum, name, name_len)) < -1)
2674       {				/* no candidate sg device file name found, try /dev/sg0,1 */
2675 	if ((dev_fd = lx_mk_devicename (0, name, name_len)) < -1)
2676 	  {
2677 	    if ((dev_fd = lx_mk_devicename (1, name, name_len)) < -1)
2678 	      return 0;		/* no luck finding sg fd to open */
2679 	  }
2680       }
2681     if (dev_fd >= 0)
2682       {
2683 /* now check this fd for match on <host, channel, id, lun> */
2684 	if (lx_chk_id (dev_fd, host, channel, id, lun))
2685 	  {
2686 	    close (dev_fd);
2687 	    DBG (1, "lx_chk_devicename: matched device(direct): %s\n", name);
2688 	    return 1;
2689 	  }
2690 	close (dev_fd);
2691       }
2692 /* if mismatch then call scan algorithm */
2693     if (lx_scan_sg (guess_devnum, name, name_len, host, channel, id, lun))
2694       {
2695 	DBG (1, "lx_chk_devicename: matched device(scan): %s\n", name);
2696 	return 1;
2697       }
2698     return 0;
2699   }
2700 
2701 /* Legacy /proc/scsi/scsi */
2702 static void /* calls 'attach' function pointer with sg device file name iff match */
sanei_proc_scsi_find_devices(const char * findvendor,const char * findmodel,const char * findtype,int findbus,int findchannel,int findid,int findlun,SANE_Status (* attach)(const char * dev))2703 sanei_proc_scsi_find_devices (const char *findvendor, const char *findmodel,
2704 			      const char *findtype,
2705 			      int findbus, int findchannel, int findid,
2706 			      int findlun,
2707 			      SANE_Status (*attach) (const char *dev))
2708   {
2709 #define FOUND_VENDOR  1
2710 #define FOUND_MODEL   2
2711 #define FOUND_TYPE    4
2712 #define FOUND_REV     8
2713 #define FOUND_HOST    16
2714 #define FOUND_CHANNEL 32
2715 #define FOUND_ID      64
2716 #define FOUND_LUN     128
2717 #define FOUND_ALL     255
2718 
2719     char *me = "sanei_proc_scsi_find_devices";
2720 
2721     size_t findvendor_len = 0, findmodel_len = 0, findtype_len = 0;
2722     char vendor[32], model[32], type[32], revision[32];
2723     int bus, channel, id, lun;
2724 
2725     int number, i, j, definedd;
2726     char line[256], dev_name[128], *c1, *c2, ctmp;
2727     char *string;
2728     FILE *proc_fp;
2729     char *end;
2730     struct
2731     {
2732       const char *name;
2733       size_t name_len;
2734       int is_int;		/* integer valued? (not a string) */
2735       union
2736       {
2737 	void *v;		/* avoids compiler warnings... */
2738 	char *str;
2739 	int *i;
2740       }
2741       u;
2742     }
2743     param[] =
2744     {
2745       {
2746 	"Vendor:", 7, 0,
2747 	{
2748 	0}
2749       }
2750       ,
2751       {
2752 	"Model:", 6, 0,
2753 	{
2754 	0}
2755       }
2756       ,
2757       {
2758 	"Type:", 5, 0,
2759 	{
2760 	0}
2761       }
2762       ,
2763       {
2764 	"Rev:", 4, 0,
2765 	{
2766 	0}
2767       }
2768       ,
2769       {
2770 	"scsi", 4, 1,
2771 	{
2772 	0}
2773       }
2774       ,
2775       {
2776 	"Channel:", 8, 1,
2777 	{
2778 	0}
2779       }
2780       ,
2781       {
2782 	"Id:", 3, 1,
2783 	{
2784 	0}
2785       }
2786       ,
2787       {
2788 	"Lun:", 4, 1,
2789 	{
2790 	0}
2791       }
2792     };
2793 
2794     param[0].u.str = vendor;
2795     param[1].u.str = model;
2796     param[2].u.str = type;
2797     param[3].u.str = revision;
2798     param[4].u.i = &bus;
2799     param[5].u.i = &channel;
2800     param[6].u.i = &id;
2801     param[7].u.i = &lun;
2802 
2803     DBG_INIT ();
2804 
2805     proc_fp = fopen (PROCFILE, "r");
2806     if (!proc_fp)
2807       {
2808 	DBG (1, "%s: could not open %s for reading\n", me, PROCFILE);
2809 	return;
2810       }
2811 
2812     number = bus = channel = id = lun = -1;
2813 
2814     vendor[0] = model[0] = type[0] = '\0';
2815     if (findvendor)
2816       findvendor_len = strlen (findvendor);
2817     if (findmodel)
2818       findmodel_len = strlen (findmodel);
2819     if (findtype)
2820       findtype_len = strlen (findtype);
2821 
2822     definedd = 0;
2823     while (!feof (proc_fp))
2824       {
2825 	fgets (line, sizeof (line), proc_fp);
2826 	string = (char *) sanei_config_skip_whitespace (line);
2827 
2828 	while (*string)
2829 	  {
2830 	    for (i = 0; i < NELEMS (param); ++i)
2831 	      {
2832 		if (strncmp (string, param[i].name, param[i].name_len) == 0)
2833 		  {
2834 		    string += param[i].name_len;
2835 		    /* Make sure that we don't read the next parameter name
2836 		       as a value, if the real value consists only of spaces
2837 		     */
2838 		    c2 = string + strlen (string);
2839 		    for (j = 0; j < NELEMS (param); ++j)
2840 		      {
2841 			c1 = strstr (string, param[j].name);
2842 			if ((j != i) && c1 && (c1 < c2))
2843 			  c2 = c1;
2844 		      }
2845 		    ctmp = *c2;
2846 		    *c2 = 0;
2847 		    string = (char *) sanei_config_skip_whitespace (string);
2848 
2849 		    if (param[i].is_int)
2850 		      {
2851 			if (*string)
2852 			  {
2853 			    *param[i].u.i = strtol (string, &end, 10);
2854 			    string = (char *) end;
2855 			  }
2856 			else
2857 			  *param[i].u.i = 0;
2858 		      }
2859 		    else
2860 		      {
2861 			strncpy (param[i].u.str, string, 32);
2862 			param[i].u.str[31] = '\0';
2863 			/* while (*string && !isspace (*string))
2864 			   ++string;
2865 			 */
2866 		      }
2867 		    /* string = sanei_config_skip_whitespace (string); */
2868 		    *c2 = ctmp;
2869 		    string = c2;
2870 		    definedd |= 1 << i;
2871 
2872 		    if (param[i].u.v == &bus)
2873 		      {
2874 			++number;
2875 			definedd = FOUND_HOST;
2876 		      }
2877 		    break;
2878 		  }
2879 	      }
2880 	    if (i >= NELEMS (param))
2881 	      ++string;		/* no match */
2882 	  }
2883 
2884 	if (FOUND_ALL != definedd)
2885 	  /* some info is still missing */
2886 	  continue;
2887 
2888 	definedd = 0;
2889 	if ((!findvendor || strncmp (vendor, findvendor, findvendor_len) == 0)
2890 	    && (!findmodel || strncmp (model, findmodel, findmodel_len) == 0)
2891 	    && (!findtype || strncmp (type, findtype, findtype_len) == 0)
2892 	    && (findbus == -1 || bus == findbus)
2893 	    && (findchannel == -1 || channel == findchannel)
2894 	    && (findid == -1 || id == findid)
2895 	    && (findlun == -1 || lun == findlun))
2896 	  {
2897 	    DBG (2, "%s: found: vendor=%s model=%s type=%s\n\t"
2898 		 "bus=%d chan=%d id=%d lun=%d num=%d\n",
2899 		 me, findvendor, findmodel, findtype,
2900 		 bus, channel, id, lun, number);
2901 	    if (lx_chk_devicename (number, dev_name, sizeof (dev_name), bus,
2902 				   channel, id, lun)
2903 		&& ((*attach) (dev_name) != SANE_STATUS_GOOD))
2904 	      {
2905 		DBG(1,"sanei_scsi_find_devices: bad attach\n");
2906 	      }
2907 	  }
2908 	else
2909 	  {
2910 	    DBG (2, "%s: no match\n", me);
2911 	  }
2912 	vendor[0] = model[0] = type[0] = 0;
2913 	bus = channel = id = lun = -1;
2914       }
2915     fclose (proc_fp);
2916   }
2917 
2918 #define SYSFS_SCSI_DEVICES "/sys/bus/scsi/devices"
2919 
2920 /* From linux/drivers/scsi/scsi.c */
2921 static char *lnxscsi_device_types[] = {
2922   "Direct-Access    ",
2923   "Sequential-Access",
2924   "Printer          ",
2925   "Processor        ",
2926   "WORM             ",
2927   "CD-ROM           ",
2928   "Scanner          ",
2929   "Optical Device   ",
2930   "Medium Changer   ",
2931   "Communications   ",
2932   "ASC IT8          ",
2933   "ASC IT8          ",
2934   "RAID             ",
2935   "Enclosure        ",
2936   "Direct-Access-RBC",
2937   "Optical card     ",
2938   "Bridge controller",
2939   "Object storage   ",
2940   "Automation/Drive "
2941 };
2942 
2943 void /* calls 'attach' function pointer with sg device file name iff match */
sanei_scsi_find_devices(const char * findvendor,const char * findmodel,const char * findtype,int findbus,int findchannel,int findid,int findlun,SANE_Status (* attach)(const char * dev))2944 sanei_scsi_find_devices (const char *findvendor, const char *findmodel,
2945 			 const char *findtype,
2946 			 int findbus, int findchannel, int findid,
2947 			 int findlun,
2948 			 SANE_Status (*attach) (const char *dev))
2949   {
2950     char *me = "sanei_scsi_find_devices";
2951     char path[PATH_MAX];
2952     char dev_name[128];
2953     struct dirent *buf;
2954     DIR *scsidevs;
2955     FILE *fp;
2956     char *ptr;
2957     char *end;
2958     int bcil[4]; /* bus, channel, id, lun */
2959     char vmt[3][33]; /* vendor, model, type */
2960     int vmt_len[3];
2961     char *vmtfiles[3] = { "vendor", "model", "type" };
2962     int lastbus;
2963     int number;
2964     int i;
2965     long val;
2966     int ret;
2967 
2968     DBG_INIT ();
2969 
2970     DBG (2, "%s: looking for: v=%s m=%s t=%s b=%d c=%d i=%d l=%d\n",
2971 	 me, findvendor, findmodel, findtype,
2972 	 findbus, findchannel, findid, findlun);
2973 
2974     scsidevs = opendir (SYSFS_SCSI_DEVICES);
2975     if (!scsidevs)
2976       {
2977 	DBG (1, "%s: could not open %s; falling back to /proc\n",
2978 	     me, SYSFS_SCSI_DEVICES);
2979 
2980 	sanei_proc_scsi_find_devices (findvendor, findmodel, findtype,
2981 				      findbus, findchannel, findid, findlun,
2982 				      attach);
2983 	return;
2984       }
2985 
2986     vmt_len[0] = (findvendor) ? strlen(findvendor) : 0;
2987     vmt_len[1] = (findmodel) ? strlen(findmodel) : 0;
2988     vmt_len[2] = (findtype) ? strlen(findtype) : 0;
2989 
2990     lastbus = -1;
2991     number = -1;
2992     for (;;)
2993       {
2994 	errno = 0;
2995 	buf = readdir (scsidevs);
2996 	if (errno != 0)
2997 	  {
2998 	    DBG (1, "%s: could not read directory %s: %s\n",
2999 		 me, SYSFS_SCSI_DEVICES, strerror(errno));
3000 
3001 	    break;
3002 	  }
3003 
3004 	if (buf == NULL)
3005 	  break;
3006 
3007 	if (buf->d_name[0] == '.')
3008 	  continue;
3009 
3010 	/* Extract bus, channel, id, lun from directory name b:c:i:l */
3011 	ptr = buf->d_name;
3012 	for (i = 0; i < 4; i++)
3013 	  {
3014 	    errno = 0;
3015 	    val = strtol (ptr, &end, 10);
3016 	    if (((errno == ERANGE) && ((val == LONG_MAX) || (val == LONG_MIN)))
3017 		|| ((errno != 0) && (val == 0)))
3018 	      {
3019 		DBG (1, "%s: invalid integer in string (%s): %s\n",
3020 		     me, ptr, strerror(errno));
3021 
3022 		i = 12; /* Skip */
3023 		break;
3024 	      }
3025 
3026 	    if (end == ptr)
3027 	      {
3028 		DBG (1, "%s: no integer found in string: %s (%d)\n", me, ptr, i);
3029 
3030 		i = 12; /* Skip */
3031 		break;
3032 	      }
3033 
3034 	    if (*end && (*end != ':'))
3035 	      {
3036 		DBG (1, "%s: parse error on string %s (%d)\n", me, buf->d_name, i);
3037 
3038 		i = 12; /* Skip */
3039 		break;
3040 	      }
3041 
3042 	    if (val > INT_MAX)
3043 	      {
3044 		DBG (1, "%s: integer value too large (%s)\n", me, buf->d_name);
3045 
3046 		i = 12; /* Skip */
3047 		break;
3048 	      }
3049 
3050 	    bcil[i] = (int) val;
3051 	    ptr = end + 1;
3052 	  }
3053 
3054 	/* Skip this one */
3055 	if (i == 12)
3056 	  continue;
3057 
3058 	if (bcil[0] != lastbus)
3059 	  {
3060 	    lastbus = bcil[0];
3061 	    number++;
3062 	  }
3063 
3064 	for (i = 0; i < 3; i++)
3065 	  {
3066 	    ret = snprintf (path, PATH_MAX, "%s/%s/%s",
3067 			   SYSFS_SCSI_DEVICES, buf->d_name, vmtfiles[i]);
3068 	    if ((ret < 0) || (ret >= PATH_MAX))
3069 	      {
3070 		DBG (1, "%s: skipping %s/%s, PATH_MAX exceeded on %s\n",
3071 		     me, SYSFS_SCSI_DEVICES, buf->d_name, vmtfiles[i]);
3072 
3073 		i = 12; /* Skip */
3074 		break;
3075 	      }
3076 
3077 	    memset (vmt[i], 0, sizeof(vmt[i]));
3078 
3079 	    fp = fopen(path, "r");
3080 	    if (!fp)
3081 	      {
3082 		DBG (1, "%s: could not open %s: %s\n", me, path, strerror(errno));
3083 
3084 		i = 12; /* Skip */
3085 		break;
3086 	      }
3087 
3088 	    ret = fread (vmt[i], 1, sizeof(vmt[i]) - 1, fp);
3089 	    if (ret <= 0)
3090 	      {
3091 		if (ferror(fp))
3092 		  {
3093 		    DBG (1, "%s: error reading %s\n", me, path);
3094 
3095 		    i = 12; /* Skip */
3096 		    break;
3097 		  }
3098 	      }
3099 
3100 	    if (vmt[i][ret - 1] == '\n')
3101 	      vmt[i][ret - 1] = '\0';
3102 
3103 	    fclose (fp);
3104 	  }
3105 
3106 	/* Skip this one */
3107 	if (i == 12)
3108 	  continue;
3109 
3110 	/* Type is a numeric string and must be converted back to a well-known string */
3111 	errno = 0;
3112 	val = strtol (vmt[2], &end, 10);
3113 	if (((errno == ERANGE) && ((val == LONG_MAX) || (val == LONG_MIN)))
3114 	    || ((errno != 0) && (val == 0)))
3115 	  {
3116 	    DBG (1, "%s: invalid integer in type string (%s): %s\n",
3117 		 me, vmt[2], strerror(errno));
3118 	    continue;
3119 	  }
3120 
3121 	if (end == vmt[2])
3122 	  {
3123 	    DBG (1, "%s: no integer found in type string: %s\n", me, vmt[2]);
3124 	    continue;
3125 	  }
3126 
3127 	if ((val < 0) || (val >= (int)(sizeof(lnxscsi_device_types) / sizeof(lnxscsi_device_types[0]))))
3128 	  {
3129 	    DBG (1, "%s: invalid type %ld\n", me, val);
3130 	    continue;
3131 	  }
3132 
3133 	strncpy(vmt[2], lnxscsi_device_types[val], sizeof(vmt[2]) - 1);
3134 
3135 	if ((!findvendor || strncmp (vmt[0], findvendor, vmt_len[0]) == 0)
3136 	    && (!findmodel || strncmp (vmt[1], findmodel, vmt_len[1]) == 0)
3137 	    && (!findtype || strncmp (vmt[2], findtype, vmt_len[2]) == 0)
3138 	    && (findbus == -1 || bcil[0] == findbus)
3139 	    && (findchannel == -1 || bcil[1] == findchannel)
3140 	    && (findid == -1 || bcil[2] == findid)
3141 	    && (findlun == -1 || bcil[3] == findlun))
3142 	  {
3143 	    DBG (2, "%s: found: vendor=%s model=%s type=%s\n\t"
3144 		 "bus=%d chan=%d id=%d lun=%d num=%d\n",
3145 		 me, vmt[0], vmt[1], vmt[2],
3146 		 bcil[0], bcil[1], bcil[2], bcil[3], number);
3147 
3148 	    if (lx_chk_devicename (number, dev_name, sizeof (dev_name),
3149 				   bcil[0], bcil[1], bcil[2], bcil[3])
3150 		&& ((*attach) (dev_name) != SANE_STATUS_GOOD))
3151 	      {
3152 		DBG (1, "%s: bad attach\n", me);
3153 	      }
3154 	  }
3155 	else
3156 	  {
3157 	    DBG (2, "%s: no match\n", me);
3158 	  }
3159       }
3160 
3161     closedir(scsidevs);
3162   }
3163 
3164 #endif /* USE == LINUX_INTERFACE */
3165 
3166 
3167 #if USE == BSD_INTERFACE
3168 
3169 #ifndef HAVE_SCSIREQ_ENTER
scsireq_enter(int fd,scsireq_t * hdr)3170   static int scsireq_enter (int fd, scsireq_t * hdr)
3171   {
3172     return ioctl (fd, SCIOCCOMMAND, hdr);
3173   }
3174 #endif /* !HAVE_SCSIREQ_ENTER */
3175 
3176   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)3177     sanei_scsi_cmd2 (int fd,
3178 		     const void *cmd, size_t cmd_size,
3179 		     const void *src, size_t src_size,
3180 		     void *dst, size_t * dst_size)
3181   {
3182     /* xxx obsolete: size_t cdb_size;
3183      */
3184     scsireq_t hdr;
3185     int result;
3186 
3187 /* xxx obsolete:
3188   cdb_size = CDB_SIZE (*(u_char *) src);
3189 */
3190 
3191     memset (&hdr, 0, sizeof (hdr));
3192     memcpy (hdr.cmd, cmd, cmd_size);
3193     if (dst_size && *dst_size)
3194       {
3195 	/* xxx obsolete: assert (cdb_size == src_size);
3196 	 */
3197 	hdr.flags = SCCMD_READ;
3198 	hdr.databuf = dst;
3199 	hdr.datalen = *dst_size;
3200       }
3201     else
3202       {
3203 	/* xxx obsolete: assert (cdb_size <= src_size);
3204 	 */
3205 	hdr.flags = SCCMD_WRITE;
3206 	/* The old variant:
3207 	   hdr.databuf = (char *) src + cdb_size;
3208 	   hdr.datalen = src_size;
3209 	   xxxxxx huh? Shouldn´t the above line have been src_size - cdb_size)
3210 	 */
3211 	hdr.databuf = (char *) src;
3212 	hdr.datalen = src_size;
3213       }
3214     hdr.timeout = sane_scsicmd_timeout * 1000;
3215     hdr.cmdlen = cmd_size;
3216     hdr.senselen = sizeof (hdr.sense);
3217 
3218     result = scsireq_enter (fd, &hdr);
3219     if (result < 0)
3220       {
3221 	DBG (1, "sanei_scsi_cmd: scsi_reqenter() failed: %s\n",
3222 	     strerror (errno));
3223 	return SANE_STATUS_IO_ERROR;
3224       }
3225     if (hdr.retsts != SCCMD_OK)
3226       {
3227 	SANEI_SCSI_Sense_Handler handler;
3228 
3229 	DBG (1, "sanei_scsi_cmd: scsi returned with status %d\n", hdr.retsts);
3230 	switch (hdr.retsts)
3231 	  {
3232 	  case SCCMD_TIMEOUT:
3233 	  case SCCMD_BUSY:
3234 	    return SANE_STATUS_DEVICE_BUSY;
3235 
3236 	  case SCCMD_SENSE:
3237 	    handler = fd_info[fd].sense_handler;
3238 	    if (handler)
3239 	      return (*handler) (fd, &hdr.sense[0],
3240 				 fd_info[fd].sense_handler_arg);
3241 	    /* fall through */
3242 	  default:
3243 	    return SANE_STATUS_IO_ERROR;
3244 	  }
3245       }
3246 
3247     if (dst_size)
3248       *dst_size = hdr.datalen_used;
3249 
3250     return SANE_STATUS_GOOD;
3251   }
3252 #endif /* USE == BSD_INTERFACE */
3253 
3254 #if USE == FREEBSD_CAM_INTERFACE
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)3255   SANE_Status sanei_scsi_cmd2 (int fd,
3256 			       const void *cmd, size_t cmd_size,
3257 			       const void *src, size_t src_size,
3258 			       void *dst, size_t * dst_size)
3259   {
3260 
3261     struct cam_device *dev;
3262     union ccb *ccb;
3263     int rv;
3264     u_int32_t ccb_flags;
3265     char *data_buf;
3266     size_t data_len;
3267     SANE_Status status;
3268 
3269     if (fd < 0 || fd > CAM_MAXDEVS || cam_devices[fd] == NULL)
3270       {
3271 	fprintf (stderr, "attempt to reference invalid unit %d\n", fd);
3272 	return SANE_STATUS_INVAL;
3273       }
3274 
3275     dev = cam_devices[fd];
3276     ccb = cam_getccb (dev);
3277 
3278     /* Build the CCB */
3279     memset (&(&ccb->ccb_h)[1], 0, sizeof (struct ccb_scsiio));
3280     memcpy (&ccb->csio.cdb_io.cdb_bytes, cmd, cmd_size);
3281 
3282     /*
3283      * Set the data direction flags.
3284      */
3285     if (dst_size && *dst_size)
3286       {
3287 	/* xxx obsolete: assert (cdb_size == src_size);
3288 	 */
3289 	ccb_flags = CAM_DIR_IN;
3290 	data_buf = ((char *) (dst));
3291 	data_len = *dst_size;
3292       }
3293     else if (src_size > 0)
3294       {
3295 	ccb_flags = CAM_DIR_OUT;
3296 	data_buf = ((char *) (src));
3297 	data_len = src_size;
3298       }
3299     else
3300       {
3301 	ccb_flags = CAM_DIR_NONE;
3302 	data_buf = NULL;
3303 	data_len = 0;
3304       }
3305 
3306     cam_fill_csio (&ccb->csio,
3307 		   /* retries */ 1,
3308 		   /* cbfncp */ NULL,
3309 		   /* flags */ ccb_flags,
3310 		   /* tag_action */ MSG_SIMPLE_Q_TAG,
3311 		   /* data_ptr */ (u_int8_t *) data_buf,
3312 		   /* dxfer_len */ data_len,
3313 		   /* sense_len */ SSD_FULL_SIZE,
3314 		   /* cdb_len */ cmd_size,
3315 		   /* timeout */ sane_scsicmd_timeout * 1000);
3316 
3317     /* Run the command */
3318     errno = 0;
3319     if ((rv = cam_send_ccb (dev, ccb)) == -1)
3320       {
3321 	cam_freeccb (ccb);
3322 	return (SANE_STATUS_IO_ERROR);
3323       }
3324 
3325     if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
3326       {
3327 	SANEI_SCSI_Sense_Handler handler;
3328 
3329 	DBG (1, "sanei_scsi_cmd: scsi returned with status %d\n",
3330 	     (ccb->ccb_h.status & CAM_STATUS_MASK));
3331 
3332 	switch (ccb->ccb_h.status & CAM_STATUS_MASK)
3333 	  {
3334 	  case CAM_BUSY:
3335 	  case CAM_SEL_TIMEOUT:
3336 	  case CAM_SCSI_BUSY:
3337 	    status = SANE_STATUS_DEVICE_BUSY;
3338 	    break;
3339 	  default:
3340 	    status = SANE_STATUS_IO_ERROR;
3341 	  }
3342 
3343 	handler = fd_info[fd].sense_handler;
3344 	if (handler && (ccb->ccb_h.status & CAM_AUTOSNS_VALID))
3345 	  {
3346 	    SANE_Status st = (*handler)
3347 	      (fd, ((u_char *) (&ccb->csio.sense_data)),
3348 	       fd_info[fd].sense_handler_arg);
3349 	    cam_freeccb (ccb);
3350 	    return st;
3351 	  }
3352 	else
3353 	  {
3354 	    cam_freeccb (ccb);
3355 	    return status;
3356 	  }
3357       }
3358     cam_freeccb (ccb);
3359     return SANE_STATUS_GOOD;
3360   }
3361 
3362 #define WE_HAVE_FIND_DEVICES
3363 
3364   int
cam_compare_inquiry(int fd,path_id_t path_id,target_id_t target_id,lun_id_t target_lun,const char * vendor,const char * product,const char * type)3365     cam_compare_inquiry (int fd, path_id_t path_id,
3366 			 target_id_t target_id, lun_id_t target_lun,
3367 			 const char *vendor, const char *product,
3368 			 const char *type)
3369   {
3370     struct ccb_dev_match cdm;
3371     struct device_match_pattern *pattern;
3372     struct scsi_inquiry_data *inq;
3373     int retval = 0;
3374 
3375     /* build ccb for device match */
3376     memset (&cdm, 0, sizeof (cdm));
3377     cdm.ccb_h.func_code = XPT_DEV_MATCH;
3378 
3379     /* result buffer */
3380     cdm.match_buf_len = sizeof (struct dev_match_result);
3381     cdm.matches = (struct dev_match_result *) malloc (cdm.match_buf_len);
3382     cdm.num_matches = 0;
3383 
3384     /* pattern buffer */
3385     cdm.num_patterns = 1;
3386     cdm.pattern_buf_len = sizeof (struct dev_match_pattern);
3387     cdm.patterns = (struct dev_match_pattern *) malloc (cdm.pattern_buf_len);
3388 
3389     /* assemble conditions */
3390     cdm.patterns[0].type = DEV_MATCH_DEVICE;
3391     pattern = &cdm.patterns[0].pattern.device_pattern;
3392     pattern->flags = DEV_MATCH_PATH | DEV_MATCH_TARGET | DEV_MATCH_LUN;
3393     pattern->path_id = path_id;
3394     pattern->target_id = target_id;
3395     pattern->target_lun = target_lun;
3396 
3397     if (ioctl (fd, CAMIOCOMMAND, &cdm) == -1)
3398       {
3399 	DBG (1, "error sending CAMIOCOMMAND ioctl");
3400 	retval = -1;
3401 	goto ret;
3402       }
3403 
3404     if ((cdm.ccb_h.status != CAM_REQ_CMP)
3405 	|| ((cdm.status != CAM_DEV_MATCH_LAST)
3406 	    && (cdm.status != CAM_DEV_MATCH_MORE)))
3407       {
3408 	DBG (1, "got CAM error %#x, CDM error %d\n",
3409 	     cdm.ccb_h.status, cdm.status);
3410 	retval = -1;
3411 	goto ret;
3412       }
3413 
3414     if (cdm.num_matches == 0)
3415       {
3416 	DBG (1, "not found\n");
3417 	retval = -1;
3418 	goto ret;
3419       }
3420 
3421     if (cdm.matches[0].type != DEV_MATCH_DEVICE)
3422       {
3423 	DBG (1, "no device match\n");
3424 	retval = -1;
3425 	goto ret;
3426       }
3427 
3428     inq = &cdm.matches[0].result.device_result.inq_data;
3429     if ((vendor && cam_strmatch (inq->vendor, vendor, SID_VENDOR_SIZE)) ||
3430 	(product && cam_strmatch (inq->product, product, SID_PRODUCT_SIZE)))
3431       retval = 1;
3432 
3433   ret:
3434     free (cdm.patterns);
3435     free (cdm.matches);
3436     return (retval);
3437   }
3438 
3439   void
sanei_scsi_find_devices(const char * findvendor,const char * findmodel,const char * findtype,int findbus,int findchannel,int findid,int findlun,SANE_Status (* attach)(const char * dev))3440     sanei_scsi_find_devices (const char *findvendor, const char *findmodel,
3441 			     const char *findtype,
3442 			     int findbus, int findchannel, int findid,
3443 			     int findlun,
3444 			     SANE_Status (*attach) (const char *dev))
3445   {
3446     int fd;
3447     struct ccb_dev_match cdm;
3448     struct periph_match_pattern *pattern;
3449     struct periph_match_result *result;
3450     int i;
3451     char devname[16];
3452 
3453     DBG_INIT ();
3454 
3455     if ((fd = open (XPT_DEVICE, O_RDWR)) == -1)
3456       {
3457 	DBG (1, "could not open %s\n", XPT_DEVICE);
3458 	return;
3459       }
3460 
3461     /* build ccb for device match */
3462     memset (&cdm, 0, sizeof (cdm));
3463     cdm.ccb_h.func_code = XPT_DEV_MATCH;
3464 
3465     /* result buffer */
3466     cdm.match_buf_len = sizeof (struct dev_match_result) * 100;
3467     cdm.matches = (struct dev_match_result *) malloc (cdm.match_buf_len);
3468     cdm.num_matches = 0;
3469 
3470     /* pattern buffer */
3471     cdm.num_patterns = 1;
3472     cdm.pattern_buf_len = sizeof (struct dev_match_pattern);
3473     cdm.patterns = (struct dev_match_pattern *) malloc (cdm.pattern_buf_len);
3474 
3475     /* assemble conditions ... findchannel is ignored */
3476     cdm.patterns[0].type = DEV_MATCH_PERIPH;
3477     pattern = &cdm.patterns[0].pattern.periph_pattern;
3478     pattern->flags = PERIPH_MATCH_NAME;
3479     strcpy (pattern->periph_name, "pass");
3480     if (findbus != -1)
3481       {
3482 	pattern->path_id = findbus;
3483 	pattern->flags |= PERIPH_MATCH_PATH;
3484       }
3485     if (findid != -1)
3486       {
3487 	pattern->target_id = findid;
3488 	pattern->flags |= PERIPH_MATCH_TARGET;
3489       }
3490     if (findlun != -1)
3491       {
3492 	pattern->target_lun = findlun;
3493 	pattern->flags |= PERIPH_MATCH_LUN;
3494       }
3495 
3496     /* result loop */
3497     do
3498       {
3499 	if (ioctl (fd, CAMIOCOMMAND, &cdm) == -1)
3500 	  {
3501 	    DBG (1, "error sending CAMIOCOMMAND ioctl");
3502 	    break;
3503 	  }
3504 
3505 	if ((cdm.ccb_h.status != CAM_REQ_CMP)
3506 	    || ((cdm.status != CAM_DEV_MATCH_LAST)
3507 		&& (cdm.status != CAM_DEV_MATCH_MORE)))
3508 	  {
3509 	    DBG (1, "got CAM error %#x, CDM error %d\n",
3510 		 cdm.ccb_h.status, cdm.status);
3511 	    break;
3512 	  }
3513 
3514 	for (i = 0; i < cdm.num_matches; i++)
3515 	  {
3516 	    if (cdm.matches[i].type != DEV_MATCH_PERIPH)
3517 	      continue;
3518 	    result = &cdm.matches[i].result.periph_result;
3519 	    DBG (4, "%s%d on scbus%d %d:%d\n",
3520 		 result->periph_name, result->unit_number,
3521 		 result->path_id, result->target_id, result->target_lun);
3522 	    if (cam_compare_inquiry (fd, result->path_id,
3523 				     result->target_id, result->target_lun,
3524 				     findvendor, findmodel, findtype) == 0)
3525 	      {
3526 		sprintf (devname, "/dev/%s%d", result->periph_name,
3527 			 result->unit_number);
3528 		(*attach) (devname);
3529 	      }
3530 	  }
3531       }
3532     while ((cdm.ccb_h.status == CAM_REQ_CMP)
3533 	   && (cdm.status == CAM_DEV_MATCH_MORE));
3534 
3535     free (cdm.patterns);
3536     free (cdm.matches);
3537     close (fd);
3538     return;
3539   }
3540 
3541 #endif
3542 
3543 
3544 
3545 #if USE == HPUX_INTERFACE
3546 /* XXX untested code! */
3547   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)3548     sanei_scsi_cmd2 (int fd,
3549 		     const void *cmd, size_t cmd_size,
3550 		     const void *src, size_t src_size,
3551 		     void *dst, size_t * dst_size)
3552   {
3553     struct sctl_io hdr;
3554     /* xxx obsolete size_t cdb_size;
3555 
3556        cdb_size = CDB_SIZE (*(u_char *) src);
3557      */
3558 
3559     memset (&hdr, 0, sizeof (hdr));
3560     memcpy (hdr.cdb, cmd, cmd_size);
3561     if (dst_size && *dst_size)
3562       {
3563 	/* xxx obsolete assert (cdb_size == src_size);
3564 	 */
3565 	hdr.flags = SCTL_READ;
3566 	hdr.data = dst;
3567 	hdr.data_length = *dst_size;
3568       }
3569     else
3570       {
3571 	/* xxx obsolete assert (cdb_size <= src_size);
3572 	 */
3573 	hdr.data = (char *) src;
3574 	hdr.data_length = src_size;
3575       }
3576     hdr.cdb_length = cmd_size;
3577     hdr.max_msecs = sane_scsicmd_timeout * 1000;
3578     if (ioctl (fd, SIOC_IO, &hdr) < 0)
3579       {
3580 	DBG (1, "sanei_scsi_cmd: ioctl(SIOC_IO) failed: %s\n",
3581 	     strerror (errno));
3582 	return SANE_STATUS_IO_ERROR;
3583       }
3584     if (hdr.cdb_status)
3585       DBG (1, "sanei_scsi_cmd: SCSI completed with cdb_status=%d\n",
3586 	   hdr.cdb_status);
3587     if (dst_size)
3588       *dst_size = hdr.data_xfer;
3589 
3590     if (hdr.sense_xfer > 0 && (hdr.sense[0] & 0x80)
3591 	&& fd_info[fd].sense_handler)
3592       return (*fd_info[fd].sense_handler) (fd, hdr.sense,
3593 					   fd_info[fd].sense_handler_arg);
3594     return SANE_STATUS_GOOD;
3595   }
3596 #endif /* USE == HPUX_INTERFACE */
3597 
3598 
3599 #if USE == OPENSTEP_INTERFACE
3600   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)3601     sanei_scsi_cmd2 (int fd,
3602 		     const void *cmd, size_t cmd_size,
3603 		     const void *src, size_t src_size,
3604 		     void *dst, size_t * dst_size)
3605   {
3606     struct scsi_req hdr;
3607     /* xxx obsolete size_t cdb_size;
3608 
3609        cdb_size = CDB_SIZE (*(u_char *) src);
3610      */
3611 
3612     memset (&hdr, 0, sizeof (hdr));
3613     memcpy (&hdr.sr_cdb, cmd, cmd_size);
3614     hdr.sr_cdb_length = cmd_size;
3615 
3616     if (dst_size && *dst_size)
3617       {
3618 	/* xxx obsolete assert (cdb_size == src_size);
3619 	 */
3620 	hdr.sr_dma_dir = SR_DMA_RD;
3621 	hdr.sr_addr = dst;
3622 	hdr.sr_dma_max = *dst_size;
3623       }
3624     else
3625       {
3626 	/* xxx obsolete assert (cdb_size <= src_size);
3627 	 */
3628 	hdr.sr_dma_dir = SR_DMA_WR;
3629 	hdr.sr_addr = (char *) src;
3630 	hdr.sr_dma_max = src_size;
3631       }
3632     hdr.sr_ioto = sane_scsicmd_timeout;
3633 
3634     if (ioctl (fd, SGIOCREQ, &hdr) == -1)
3635       {
3636 	DBG (1, "sanei_scsi_cmd: ioctl(SGIOCREQ) failed: %s\n",
3637 	     strerror (errno));
3638 	return SANE_STATUS_IO_ERROR;
3639       }
3640     if (hdr.sr_io_status != 1)
3641       DBG (1, "sanei_scsi_cmd: SGIOCREQ completed with sr_io_status=%d\n",
3642 	   hdr.sr_io_status);
3643 
3644     if (hdr.sr_io_status == SR_IOST_CHKSNV)
3645       {
3646 	struct scsi_req sr;
3647 	struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6;
3648 	struct esense_reply sense_reply;
3649 	int i;
3650 	char *p;
3651 
3652 	/* clear struct */
3653 	p = (char *) cdbp;
3654 	for (i = 0; i < sizeof (union cdb); i++)
3655 	  *p++ = 0;
3656 	memset (&sr, 0, sizeof (struct scsi_req));
3657 
3658 	cdbp->c6_opcode = C6OP_REQSENSE;
3659 	cdbp->c6_lun = 0;	/* where do I get the lun from? */
3660 	cdbp->c6_len = 0x20;
3661 	cdbp->c6_ctrl = 0;
3662 
3663 	sr.sr_dma_dir = SR_DMA_RD;
3664 	sr.sr_addr = (char *) &sense_reply;
3665 	sr.sr_dma_max = sizeof (struct esense_reply);
3666 	sr.sr_ioto = sane_scsicmd_timeout;
3667 	sr.sr_cdb_length = 6;
3668 
3669 	ioctl (fd, SGIOCREQ, &sr);
3670 	if (sense_reply.er_ibvalid)
3671 	  {
3672 	    sr.sr_esense = sense_reply;
3673 	    if (fd_info[fd].sense_handler)
3674 	      return (*fd_info[fd].sense_handler)
3675 		(fd, (u_char *) & sr.sr_esense,
3676 		 fd_info[fd].sense_handler_arg);
3677 	  }
3678 
3679 	/* sense reply is invalid */
3680 	return SANE_STATUS_INVAL;
3681       }
3682 
3683     if (hdr.sr_scsi_status == SR_IOST_CHKSV && fd_info[fd].sense_handler)
3684       return (*fd_info[fd].sense_handler) (fd, (u_char *) & hdr.sr_esense,
3685 					   fd_info[fd].sense_handler_arg);
3686     if (dst_size)
3687       *dst_size = hdr.sr_dma_xfr;
3688     return SANE_STATUS_GOOD;
3689   }
3690 #endif /* USE == OPENSTEP_INTERFACE */
3691 
3692 
3693 #if USE == DECUNIX_INTERFACE
3694   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)3695     sanei_scsi_cmd2 (int fd,
3696 		     const void *cmd, size_t cmd_size,
3697 		     const void *src, size_t src_size,
3698 		     void *dst, size_t * dst_size)
3699   {
3700     u_char sense[64];
3701     UAGT_CAM_CCB hdr;
3702     CCB_SCSIIO ccb;
3703     /* xxx obsolete size_t cdb_size;
3704 
3705        cdb_size = CDB_SIZE (*(u_char *) src);
3706      */
3707 
3708     memset (&ccb, 0, sizeof (ccb));
3709     ccb.cam_ch.my_addr = (CCB_HEADER *) & ccb;
3710     ccb.cam_ch.cam_ccb_len = sizeof (ccb);
3711     ccb.cam_ch.cam_func_code = XPT_SCSI_IO;
3712     ccb.cam_ch.cam_path_id = fd_info[fd].bus;
3713     ccb.cam_ch.cam_target_id = fd_info[fd].target;
3714     ccb.cam_ch.cam_target_lun = fd_info[fd].lun;
3715     ccb.cam_ch.cam_flags = 0;
3716 
3717     if (dst_size && *dst_size)
3718       {
3719 	/* xxx obsolete assert (cdb_size == src_size);
3720 	 */
3721 	ccb.cam_ch.cam_flags |= CAM_DIR_IN;
3722 	ccb.cam_data_ptr = (u_char *) dst;
3723 	ccb.cam_dxfer_len = *dst_size;
3724       }
3725     else
3726       {
3727 	/* xxx obsolete assert (cdb_size <= src_size);
3728 	 */
3729 	if (0 == src_size)
3730 	  ccb.cam_ch.cam_flags |= CAM_DIR_NONE;
3731 	else
3732 	  ccb.cam_ch.cam_flags |= CAM_DIR_OUT;
3733 	ccb.cam_data_ptr = (u_char *) src;
3734 	ccb.cam_dxfer_len = src_size;
3735       }
3736     ccb.cam_timeout = sane_scsicmd_timeout;
3737     ccb.cam_cdb_len = cmd_size;
3738     memcpy (&ccb.cam_cdb_io.cam_cdb_bytes[0], cmd, cmd_size);
3739 
3740     memset (&hdr, 0, sizeof (hdr));
3741     hdr.uagt_ccb = (CCB_HEADER *) & ccb;
3742     hdr.uagt_ccblen = sizeof (ccb);
3743     hdr.uagt_buffer = ccb.cam_data_ptr;
3744     hdr.uagt_buflen = ccb.cam_dxfer_len;
3745     hdr.uagt_snsbuf = sense;
3746     hdr.uagt_snslen = sizeof (sense);
3747     hdr.uagt_cdb = 0;		/* indicate that CDB is in CCB */
3748     hdr.uagt_cdblen = 0;
3749 
3750     if (ioctl (cam_fd, UAGT_CAM_IO, &hdr) < 0)
3751       {
3752 	DBG (1, "sanei_scsi_cmd: ioctl(UAGT_CAM_IO) failed: %s\n",
3753 	     strerror (errno));
3754 	return SANE_STATUS_IO_ERROR;
3755       }
3756     if (ccb.cam_ch.cam_status != CAM_REQ_CMP)
3757       {
3758 	DBG (1, "sanei_scsi_cmd: UAGT_CAM_IO completed with cam_status=%d\n",
3759 	     ccb.cam_ch.cam_status);
3760 
3761 	if (ccb.cam_ch.cam_status == CAM_AUTOSNS_VALID
3762 	    && fd_info[fd].sense_handler)
3763 	  return (*fd_info[fd].sense_handler) (fd, sense,
3764 					       fd_info[fd].sense_handler_arg);
3765 	else
3766 	  return SANE_STATUS_INVAL;
3767       }
3768     if (dst_size)
3769       *dst_size = ccb.cam_dxfer_len;
3770     return SANE_STATUS_GOOD;
3771   }
3772 #endif /* USE == DECUNIX_INTERFACE */
3773 
3774 
3775 #if USE == SCO_OS5_INTERFACE
3776   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)3777     sanei_scsi_cmd2 (int fd,
3778 		     const void *cmd, size_t cmd_size,
3779 		     const void *src, size_t src_size,
3780 		     void *dst, size_t * dst_size)
3781   {
3782     static u_char sense_buffer[256];
3783     struct scsicmd2 sc2;
3784     struct scsicmd *sc;
3785     /* xxx obsolete int cdb_size;
3786      */
3787     int opcode;
3788     int i;
3789 
3790     if (fd < 0)
3791       return SANE_STATUS_IO_ERROR;
3792 
3793     memset (&sc2, 0, sizeof (sc2));
3794     sc = &sc2.cmd;
3795     sc2.sense_len = sizeof (sense_buffer);
3796     sc2.sense_ptr = sense_buffer;
3797 
3798     /* xxx obsolete cdb_size = CDB_SIZE (*(u_char *) src);
3799      */
3800     if (dst_size && *dst_size)
3801       {
3802 	sc->is_write = 0;
3803 	sc->data_ptr = dst;
3804 	sc->data_len = *dst_size;
3805       }
3806     else
3807       {
3808 	sc->data_len = src_size;
3809 	sc->data_ptr = (char *) src;
3810 	sc->is_write = 1;
3811       }
3812     memcpy (sc->cdb, cmd, cmd_size);
3813     sc->cdb_len = cmd_size;
3814 
3815     /* Send the command down via the "pass-through" interface */
3816     if (ioctl (fd, SCSIUSERCMD2, &sc2) < 0)
3817       {
3818 	DBG (1, "sanei_scsi_cmd: ioctl(SCSIUSERCMD2) failed: %s\n",
3819 	     strerror (errno));
3820 	return SANE_STATUS_IO_ERROR;
3821       }
3822     if (sc->host_sts || sc->target_sts)
3823       {
3824 	DBG (1, "sanei_scsi_cmd: SCSIUSERCMD2 completed with "
3825 	     "host_sts=%x, target_sts=%x\n", sc->host_sts, sc->target_sts);
3826 	if (fd_info[fd].sense_handler)
3827 	  return (*fd_info[fd].sense_handler) (fd, sense_buffer,
3828 					       fd_info[fd].sense_handler_arg);
3829 	return SANE_STATUS_IO_ERROR;
3830       }
3831     return SANE_STATUS_GOOD;
3832   }
3833 #endif /* USE == SCO_OS5_INTERFACE */
3834 #if USE == SYSVR4_INTERFACE
3835 
3836 /*
3837  * UNIXWARE 2.x interface
3838  * (c) R=I+S Rapp Informatik System Germany
3839  * Email: wolfgang@rapp-informatik.de
3840  *
3841  * The driver version should run with other scsi components like disk
3842  * attached to the same controller at the same time.
3843  *
3844  * Attention : This port needs a sane kernel driver for Unixware 2.x
3845  * The driver is available in binary pkgadd format
3846  * Please mail me.
3847  *
3848  */
3849   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)3850     sanei_scsi_cmd2 (int fd,
3851 		     const void *cmd, size_t cmd_size,
3852 		     const void *src, size_t src_size,
3853 		     void *dst, size_t * dst_size)
3854   {
3855     struct sb sb, *sb_ptr;	/* Command block and pointer */
3856     struct scs *scs;		/* group 6 command pointer */
3857     struct scm *scm;		/* group 10 command pointer */
3858     struct scv *scv;		/* group 12 command pointer */
3859     char sense[32];		/* for call of sens req */
3860     char cmd[16];		/* global for right alignment */
3861     char *cp;
3862 
3863     /* xxx obsolete size_t cdb_size;
3864 
3865        cdb_size = CDB_SIZE (*(u_char *) src);
3866      */
3867     memset (&cmd, 0, 16);
3868     sb_ptr = &sb;
3869     sb_ptr->sb_type = ISCB_TYPE;
3870     cp = (char *) cmd;
3871     DBG (1,
3872 	 "cdb_size = %d src = {0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x ...}\n",
3873 	 cmd_size, cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7],
3874 	 cp[8], cp[9]);
3875     switch (cmd_size)
3876       {
3877       default:
3878 	return SANE_STATUS_IO_ERROR;
3879       case 6:
3880 	scs = (struct scs *) cmd;
3881 	memcpy (SCS_AD (scs), cmd, SCS_SZ);
3882 	scs->ss_lun = 0;
3883 	sb_ptr->SCB.sc_cmdpt = SCS_AD (scs);
3884 	sb_ptr->SCB.sc_cmdsz = SCS_SZ;
3885 	break;
3886       case 10:
3887 	scm = (struct scm *) cmd;
3888 	memcpy (SCM_AD (scm), cmd, SCM_SZ);
3889 	scm->sm_lun = 0;
3890 	sb_ptr->SCB.sc_cmdpt = SCM_AD (scm);
3891 	sb_ptr->SCB.sc_cmdsz = SCM_SZ;
3892 	break;
3893       case 12:
3894 	scv = (struct scv *) cmd;
3895 	memcpy (SCV_AD (scv), cmd, SCV_SZ);
3896 	scv->sv_lun = 0;
3897 	sb_ptr->SCB.sc_cmdpt = SCV_AD (scv);
3898 	sb_ptr->SCB.sc_cmdsz = SCV_SZ;
3899 	break;
3900       }
3901     if (dst_size && *dst_size)
3902       {
3903 	assert (0 == src_size);
3904 	sb_ptr->SCB.sc_mode = SCB_READ;
3905 	sb_ptr->SCB.sc_datapt = dst;
3906 	sb_ptr->SCB.sc_datasz = *dst_size;
3907       }
3908     else
3909       {
3910 	assert (0 <= src_size);
3911 	sb_ptr->SCB.sc_mode = SCB_WRITE;
3912 	sb_ptr->SCB.sc_datapt = (char *) src;
3913 	if ((sb_ptr->SCB.sc_datasz = src_size) > 0)
3914 	  {
3915 	    sb_ptr->SCB.sc_mode = SCB_WRITE;
3916 	  }
3917 	else
3918 	  {
3919 	    /* also use READ mode if the backends have write with length 0 */
3920 	    sb_ptr->SCB.sc_mode = SCB_READ;
3921 	  }
3922       }
3923     sb_ptr->SCB.sc_time = sane_scsicmd_timeout * 1000;
3924     DBG (1, "sanei_scsi_cmd: sc_mode = %d, sc_cmdsz = %d, sc_datasz = %d\n",
3925 	 sb_ptr->SCB.sc_mode, sb_ptr->SCB.sc_cmdsz, sb_ptr->SCB.sc_datasz);
3926     {
3927       /* do read write by normal read or write system calls */
3928       /* the driver will lock process in momory and do optimized transfer */
3929       cp = (char *) cmd;
3930       switch (*cp)
3931 	{
3932 	case 0x0:		/* test unit ready */
3933 	  if (ioctl (fd, SS_TEST, NULL) < 0)
3934 	    {
3935 	      return SANE_STATUS_DEVICE_BUSY;
3936 	    }
3937 	  break;
3938 	case SS_READ:
3939 	case SM_READ:
3940 	  if (*dst_size > 0x2048)
3941 	    {
3942 	      sb_ptr->SCB.sc_datapt = NULL;
3943 	      sb_ptr->SCB.sc_datasz = 0;
3944 	      if (memcmp
3945 		  (sb_ptr->SCB.sc_cmdpt, lastrcmd, sb_ptr->SCB.sc_cmdsz))
3946 		{
3947 		  /* set the command block for the next read or write */
3948 		  memcpy (lastrcmd, sb_ptr->SCB.sc_cmdpt,
3949 			  sb_ptr->SCB.sc_cmdsz);
3950 		  if (!ioctl (fd, SDI_SEND, sb_ptr))
3951 		    {
3952 		      *dst_size = read (fd, dst, *dst_size);
3953 		      if (*dst_size == -1)
3954 			{
3955 			  perror ("sanei-scsi:UW-driver read ");
3956 			  return SANE_STATUS_IO_ERROR;
3957 			}
3958 		      break;
3959 		    }
3960 		}
3961 	      else
3962 		{
3963 		  *dst_size = read (fd, dst, *dst_size);
3964 		  if (*dst_size == -1)
3965 		    {
3966 		      perror ("sanei-scsi:UW-driver read ");
3967 		      return SANE_STATUS_IO_ERROR;
3968 		    }
3969 		  break;
3970 		}
3971 	      return SANE_STATUS_IO_ERROR;
3972 	    }
3973 	  /* fall through for small read */
3974 	default:
3975 	  if (ioctl (fd, SDI_SEND, sb_ptr) < 0)
3976 	    {
3977 	      DBG (1, "sanei_scsi_cmd: ioctl(SDI_SEND) FAILED: %s\n",
3978 		   strerror (errno));
3979 	      return SANE_STATUS_IO_ERROR;
3980 	    }
3981 	  if (dst_size)
3982 	    *dst_size = sb_ptr->SCB.sc_datasz;
3983 #ifdef UWSUPPORTED		/* at this time not supported by driver */
3984 	  if (sb_ptr->SCB.sc_comp_code != SDI_ASW)
3985 	    {
3986 	      DBG (1, "sanei_scsi_cmd: scsi_cmd failure %x\n",
3987 		   sb_ptr->SCB.sc_comp_code);
3988 	      if (sb_ptr->SCB.sc_comp_code == SDI_CKSTAT
3989 		  && sb_ptr->SCB.sc_status == S_CKCON)
3990 		if (fd_info[fd].sense_handler)
3991 		  {
3992 		    void *arg = fd_info[fd].sense_handler_arg;
3993 		    return (*fd_info[fd].sense_handler) (fd,
3994 							 (u_char *) & sb_ptr->
3995 							 SCB.sc_link, arg);
3996 		  }
3997 	      return SANE_STATUS_IO_ERROR;
3998 	    }
3999 #endif
4000 	  break;
4001 	}
4002       return SANE_STATUS_GOOD;
4003     }
4004   }
4005 #endif /* USE == SYSVR4_INTERFACE */
4006 #if USE == SCO_UW71_INTERFACE
4007   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)4008     sanei_scsi_cmd2 (int fd,
4009 		     const void *cmd, size_t cmd_size,
4010 		     const void *src, size_t src_size,
4011 		     void *dst, size_t * dst_size)
4012   {
4013     static u_char sense_buffer[24];
4014     struct scb cmdblk;
4015     time_t elapsed;
4016     uint_t compcode, status;
4017     /* xxx obsolete int cdb_size, mode;
4018      */
4019     int mode;
4020     int i;
4021 
4022     if (fd < 0)
4023       return SANE_STATUS_IO_ERROR;
4024 
4025     cmdblk.sc_cmdpt = (caddr_t) cmd;
4026     /* xxx obsolete cdb_size = CDB_SIZE (*(u_char *) src);
4027      */
4028     cmdblk.sc_cmdsz = cmd_size;
4029     cmdblk.sc_time = 60000;	/* 60 secs */
4030 
4031     if (dst_size && *dst_size)
4032       {
4033 	/* xxx obsolete assert (cdb_size == src_size);
4034 	 */
4035 	cmdblk.sc_datapt = (caddr_t) dst;
4036 	cmdblk.sc_datasz = *dst_size;
4037 	mode = SCB_READ;
4038       }
4039     else
4040       {
4041 	/* xxx obsolete assert (cdb_size <= src_size);
4042 	 */
4043 	cmdblk.sc_datapt = (char *) src;
4044 	cmdblk.sc_datasz = src_size;
4045 	mode = SCB_WRITE;
4046       }
4047 
4048     if (pt_send (fd, cmdblk.sc_cmdpt, cmdblk.sc_cmdsz, cmdblk.sc_datapt,
4049 		 cmdblk.sc_datasz, mode, cmdblk.sc_time, &elapsed, &compcode,
4050 		 &status, sense_buffer, sizeof (sense_buffer)) != 0)
4051       {
4052 	DBG (1, "sanei_scsi_cmd: pt_send failed: %s!\n", strerror (errno));
4053       }
4054     else
4055       {
4056 	DBG (2, "sanei_scsi_cmd completed with: compcode = %x, status = %x\n",
4057 	     compcode, status);
4058 
4059 	switch (compcode)
4060 	  {
4061 	  case SDI_ASW:	/* All seems well */
4062 	    return SANE_STATUS_GOOD;
4063 	  case SDI_CKSTAT:
4064 	    DBG (2, "Sense Data:\n");
4065 	    for (i = 0; i < sizeof (sense_buffer); i++)
4066 	      DBG (2, "%.2X ", sense_buffer[i]);
4067 	    DBG (2, "\n");
4068 	    if (fd_info[fd].sense_handler)
4069 	      return (*fd_info[fd].sense_handler) (fd, sense_buffer,
4070 						   fd_info[fd].
4071 						   sense_handler_arg);
4072 	    /* fall through */
4073 	  default:
4074 	    return SANE_STATUS_IO_ERROR;
4075 	  }
4076       }
4077   }
4078 #endif /* USE == SCO_UW71_INTERFACE */
4079 
4080 #if USE == OS2_INTERFACE
4081 
4082 #define WE_HAVE_FIND_DEVICES
4083 
4084   static int
get_devicename(int bus,int target,int lun,char * name,size_t name_len)4085     get_devicename (int bus, int target, int lun, char *name, size_t name_len)
4086   {
4087     snprintf (name, name_len, "b%dt%dl%d", bus, target, lun);
4088     DBG (1, "OS/2 searched device is %s\n", name);
4089     return 0;
4090   }
4091 
4092   void
sanei_scsi_find_devices(const char * findvendor,const char * findmodel,const char * findtype,int findbus,int findchannel,int findid,int findlun,SANE_Status (* attach)(const char * dev))4093     sanei_scsi_find_devices (const char *findvendor, const char *findmodel,
4094 			     const char *findtype,
4095 			     int findbus, int findchannel, int findid,
4096 			     int findlun,
4097 			     SANE_Status (*attach) (const char *dev))
4098   {
4099     size_t findvendor_len = 0, findmodel_len = 0, findtype_len = 0;
4100     char vendor[32], model[32], type[32], revision[32];
4101     int bus, channel, id, lun, number, i;
4102     char line[256], dev_name[128];
4103     const char *string;
4104     FILE *proc_fp;
4105     char *end;
4106     struct
4107     {
4108       const char *name;
4109       size_t name_len;
4110       int is_int;		/* integer valued? (not a string) */
4111       union
4112       {
4113 	void *v;		/* avoids compiler warnings... */
4114 	char *str;
4115 	int *i;
4116       }
4117       u;
4118     }
4119     param[] =
4120     {
4121       {
4122 	"Vendor:", 7, 0,
4123 	{
4124 	0}
4125       }
4126       ,
4127       {
4128 	"Model:", 6, 0,
4129 	{
4130 	0}
4131       }
4132       ,
4133       {
4134 	"Type:", 5, 0,
4135 	{
4136 	0}
4137       }
4138       ,
4139       {
4140 	"Rev:", 4, 0,
4141 	{
4142 	0}
4143       }
4144       ,
4145       {
4146 	"scsi", 4, 1,
4147 	{
4148 	0}
4149       }
4150       ,
4151       {
4152 	"Channel:", 8, 1,
4153 	{
4154 	0}
4155       }
4156       ,
4157       {
4158 	"Id:", 3, 1,
4159 	{
4160 	0}
4161       }
4162       ,
4163       {
4164 	"Lun:", 4, 1,
4165 	{
4166 	0}
4167       }
4168     };
4169 
4170     param[0].u.str = vendor;
4171     param[1].u.str = model;
4172     param[2].u.str = type;
4173     param[3].u.str = revision;
4174     param[4].u.i = &bus;
4175     param[5].u.i = &channel;
4176     param[6].u.i = &id;
4177     param[7].u.i = &lun;
4178 
4179     DBG_INIT ();
4180 
4181     open_aspi ();		/* open aspi manager if not already done */
4182 
4183     DBG (2, "find_devices: open temporary file '%s'\n", tmpAspi);
4184     proc_fp = fopen (tmpAspi, "r");
4185     if (!proc_fp)
4186       {
4187 	DBG (1, "could not open %s for reading\n", tmpAspi);
4188 	return;
4189       }
4190 
4191     number = bus = channel = id = lun = -1;
4192 
4193     vendor[0] = model[0] = type[0] = '\0';
4194     if (findvendor)
4195       findvendor_len = strlen (findvendor);
4196     if (findmodel)
4197       findmodel_len = strlen (findmodel);
4198     if (findtype)
4199       findtype_len = strlen (findtype);
4200 
4201     while (!feof (proc_fp))
4202       {
4203 	if (!fgets (line, sizeof (line), proc_fp))
4204 	  break;		/* at eof exit */
4205 
4206 	string = sanei_config_skip_whitespace (line);
4207 
4208 	while (*string)
4209 	  {
4210 	    for (i = 0; i < NELEMS (param); ++i)
4211 	      {
4212 		if (strncmp (string, param[i].name, param[i].name_len) == 0)
4213 		  {
4214 		    string += param[i].name_len;
4215 		    string = sanei_config_skip_whitespace (string);
4216 		    if (param[i].is_int)
4217 		      {
4218 			*param[i].u.i = strtol (string, &end, 10);
4219 			string = (char *) end;
4220 		      }
4221 		    else
4222 		      {
4223 			strncpy (param[i].u.str, string, 32);
4224 			param[i].u.str[31] = '\0';
4225 			while (*string && !isspace ((int) *string))
4226 			  ++string;
4227 		      }
4228 		    string = sanei_config_skip_whitespace (string);
4229 
4230 		    if (param[i].u.v == &bus)
4231 		      ++number;
4232 		    break;
4233 		  }
4234 	      }
4235 	    if (i >= NELEMS (param))
4236 	      ++string;		/* no match */
4237 	  }
4238 
4239 	if ((findvendor && !vendor[0]) || (findmodel && !model[0])
4240 	    || (findtype && !type[0])
4241 	    || (findbus >= 0 && bus == -1) || (findchannel >= 0
4242 					       && channel == -1)
4243 	    || (findlun >= 0 && lun == -1))
4244 	  /* some info is still missing */
4245 	  continue;
4246 
4247 	if ((!findvendor || strncmp (vendor, findvendor, findvendor_len) == 0)
4248 	    && (!findmodel || strncmp (model, findmodel, findmodel_len) == 0)
4249 	    && (!findtype || strncmp (type, findtype, findtype_len) == 0)
4250 	    && (findbus == -1 || bus == findbus)
4251 	    && (findchannel == -1 || channel == findchannel)
4252 	    && (findid == -1 || id == findid)
4253 	    && (findlun == -1 || lun == findlun)
4254 	    && get_devicename (bus, id, lun, dev_name, sizeof (dev_name)) >= 0
4255 	    && (*attach) (dev_name) != SANE_STATUS_GOOD)
4256 	  return;
4257 
4258 	vendor[0] = model[0] = type[0] = 0;
4259 	bus = channel = id = lun = -1;
4260       }
4261 
4262     DBG (2, "find_devices: close temporary file '%s'\n", tmpAspi);
4263     fclose (proc_fp);
4264 
4265     close_aspi ();		/* close aspi manager */
4266   }
4267 
4268 /* XXX untested code! */
4269   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)4270     sanei_scsi_cmd2 (int fd,
4271 		     const void *cmd, size_t cmd_size,
4272 		     const void *src, size_t src_size,
4273 		     void *dst, size_t * dst_size)
4274   {
4275     ULONG rc;			/* Returns. */
4276     unsigned long cbreturn;
4277     unsigned long cbParam;
4278     if (aspi_buf == NULL)	/* avoid SIGSEGV in memcpy() when calling
4279 				   sanei_scsi_cmd2() while aspi-driver is closed */
4280       {
4281 	DBG (1, "sanei_scsi_cmd: Error no device (aspi_buf == NULL)\n");
4282 	return SANE_STATUS_INVAL;
4283       }
4284 
4285     if (PSRBlock == NULL)	/* avoid SIGSEGV in memcpy() when calling
4286 				   sanei_scsi_cmd2() while aspi-driver is closed */
4287       {
4288 	DBG (1, "sanei_scsi_cmd: Error no device (PSRBlock == NULL)\n");
4289 	return SANE_STATUS_INVAL;
4290       }
4291 
4292     memset (PSRBlock, 0, sizeof (SRB));	/* Okay, I'm paranoid. */
4293     PSRBlock->cmd = SRB_Command;	/* execute SCSI cmd */
4294     PSRBlock->ha_num = fd_info[fd].bus;	/* host adapter number */
4295     PSRBlock->u.cmd.target = fd_info[fd].target;	/* Target SCSI ID */
4296     PSRBlock->u.cmd.lun = fd_info[fd].lun;	/* Target SCSI LUN */
4297     PSRBlock->flags = SRB_Post;	/* posting enabled */
4298     if (dst_size && *dst_size)
4299       {
4300 	/* Reading. */
4301 	assert (*dst_size <= (size_t) sanei_scsi_max_request_size);
4302 	PSRBlock->u.cmd.data_len = *dst_size;
4303 	DBG (1, "sanei_scsi_cmd: Reading PSRBlock->u.cmd.data_len= %lu\n",
4304 	     PSRBlock->u.cmd.data_len);
4305 	PSRBlock->flags |= SRB_Read;
4306       }
4307     else
4308       {
4309 	/* Writing. */
4310 	PSRBlock->u.cmd.data_len = src_size;
4311 	DBG (1, "sanei_scsi_cmd: Writing PSRBlock->u.cmd.data_len= %lu\n",
4312 	     PSRBlock->u.cmd.data_len);
4313 	assert (PSRBlock->u.cmd.data_len <=
4314 		(unsigned long) sanei_scsi_max_request_size);
4315 	if (PSRBlock->u.cmd.data_len)
4316 	  PSRBlock->flags |= SRB_Write;
4317 	else
4318 	  PSRBlock->flags |= SRB_NoTransfer;
4319 	memcpy (aspi_buf, src, PSRBlock->u.cmd.data_len);
4320       }
4321     PSRBlock->u.cmd.sense_len = 32;	/* length of sense buffer */
4322     PSRBlock->u.cmd.data_ptr = NULL;	/* pointer to data buffer already registered */
4323     PSRBlock->u.cmd.link_ptr = NULL;	/* pointer to next SRB */
4324     PSRBlock->u.cmd.cdb_len = cmd_size;	/* SCSI command length */
4325     memcpy (PSRBlock->u.cmd.cdb_st, cmd, cmd_size);
4326 
4327     /* Do the command. */
4328     rc = DosDevIOCtl (driver_handle, 0x92, 0x02,
4329 		      (void *) PSRBlock, sizeof (SRB), &cbParam,
4330 		      (void *) PSRBlock, sizeof (SRB), &cbreturn);
4331 
4332     if (rc)
4333       {
4334 	DBG (1, "sanei_scsi_cmd: DosDevIOCtl failed. rc= %lu \n", rc);
4335 	return SANE_STATUS_IO_ERROR;
4336       }
4337 
4338     /* Get sense data if available. */
4339     if ((PSRBlock->status == SRB_Aborted || PSRBlock->status == SRB_Error) &&
4340 	PSRBlock->u.cmd.target_status == SRB_CheckStatus
4341 	&& fd_info[fd].sense_handler != 0)
4342       {
4343 	SANEI_SCSI_Sense_Handler s_handler = fd_info[fd].sense_handler;
4344 	return (*s_handler) (fd, &PSRBlock->u.cmd.cdb_st[cmd_size],
4345 			     fd_info[fd].sense_handler_arg);
4346       }
4347     if (PSRBlock->status != SRB_Done ||
4348 	PSRBlock->u.cmd.ha_status != SRB_NoError ||
4349 	PSRBlock->u.cmd.target_status != SRB_NoStatus)
4350       {
4351 	DBG (1, "sanei_scsi_cmd:  command 0x%02x failed.\n"
4352 	     "PSRBlock->status= 0x%02x\n"
4353 	     "PSRBlock->u.chm.ha_status= 0x%02x\n"
4354 	     "PSRBlock->u.cmd.target_status= 0x%02x\n",
4355 	     PSRBlock->u.cmd.cdb_st[0],
4356 	     PSRBlock->status,
4357 	     PSRBlock->u.cmd.ha_status, PSRBlock->u.cmd.target_status);
4358 	return SANE_STATUS_IO_ERROR;
4359       }
4360 
4361     if (dst_size && *dst_size)	/* Reading? */
4362       memcpy ((char *) dst, aspi_buf, *dst_size);
4363     return SANE_STATUS_GOOD;
4364   }
4365 #endif /* USE == OS2_INTERFACE */
4366 
4367 #if USE == STUBBED_INTERFACE
4368   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)4369     sanei_scsi_cmd2 (int fd,
4370 		     const void *cmd, size_t cmd_size,
4371 		     const void *src, size_t src_size,
4372 		     void *dst, size_t * dst_size)
4373   {
4374     return SANE_STATUS_UNSUPPORTED;
4375   }
4376 #endif /* USE == STUBBED_INTERFACE */
4377 
4378 #if USE == IRIX_INTERFACE
4379 
4380 #define WE_HAVE_FIND_DEVICES
4381 
4382   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)4383     sanei_scsi_cmd2 (int fd,
4384 		     const void *cmd, size_t cmd_size,
4385 		     const void *src, size_t src_size,
4386 		     void *dst, size_t * dst_size)
4387   {
4388     dsreq_t scsi_req;		/* SCSI request */
4389 /* xxx obsolete size_t  cdb_size; *//* Size of SCSI command */
4390     static u_char *cmdbuf = NULL,	/* Command buffer */
4391      *sensebuf = NULL,		/* Request sense buffer */
4392      *databuf = NULL;		/* Data buffer */
4393 
4394     /*
4395      * Allocate the sense and command data buffers as necessary; we have
4396      * to do this to avoid buffer alignment problems, since some
4397      * hardware requires these buffers to be 32-bit aligned.
4398      */
4399     if (cmdbuf == NULL)
4400       {
4401 	cmdbuf = malloc (64);
4402 	sensebuf = malloc (1024);	/* may be can reduced to 128 */
4403 	databuf = malloc (MAX_DATA);
4404 
4405 	if (cmdbuf == NULL || sensebuf == NULL || databuf == NULL)
4406 	  return SANE_STATUS_NO_MEM;
4407       }
4408 
4409     /*
4410      * Build the SCSI request...
4411      */
4412     /* xxx obsolete cdb_size = CDB_SIZE (*(u_char *) src);
4413      */
4414 
4415     DBG (1, "sanei_scsi_cmd: cmd_size = %d\n", cmd_size);
4416 
4417     if (dst != NULL)
4418       {
4419 	/*
4420 	 * SCSI command returning/reading data...
4421 	 */
4422 	scsi_req.ds_flags = DSRQ_READ | DSRQ_SENSE;
4423 	scsi_req.ds_time = 120 * 1000;
4424 	scsi_req.ds_cmdbuf = (caddr_t) cmdbuf;
4425 	scsi_req.ds_cmdlen = cmd_size;
4426 	scsi_req.ds_databuf = (caddr_t) databuf;
4427 	scsi_req.ds_datalen = *dst_size;
4428 	scsi_req.ds_sensebuf = (caddr_t) sensebuf;
4429 	scsi_req.ds_senselen = 128;	/* 1024 does not work, 128 is tested (O.Rauch) */
4430 
4431 	/*
4432 	 * Copy command to cmdbuf to assure 32-bit alignment.
4433 	 */
4434 	memcpy (cmdbuf, cmd, cmd_size);
4435       }
4436     else
4437       {
4438 	/*
4439 	 * SCSI command sending/writing data...
4440 	 */
4441 	scsi_req.ds_flags = DSRQ_WRITE | DSRQ_SENSE;
4442 	scsi_req.ds_time = 120 * 1000;
4443 	scsi_req.ds_cmdbuf = (caddr_t) cmdbuf;
4444 	scsi_req.ds_cmdlen = cmd_size;
4445 	scsi_req.ds_databuf = (caddr_t) databuf;
4446 	scsi_req.ds_datalen = src_size;
4447 	scsi_req.ds_sensebuf = (caddr_t) sensebuf;
4448 	scsi_req.ds_senselen = 128;
4449 
4450 	/*
4451 	 * Copy command and data to local buffers to ensure 32-bit alignment...
4452 	 */
4453 	memcpy (cmdbuf, (u_char *) cmd, cmd_size);
4454 	memcpy (databuf, (u_char *) src, src_size);
4455       }
4456 
4457     memset (sensebuf, 0, 128);
4458 
4459     /*
4460      * Do SCSI request...
4461      */
4462     if (ioctl (fd, DS_ENTER, &scsi_req) < 0)
4463       {
4464 	DBG (1, "sanei_scsi_cmd: ioctl failed - %s\n", strerror (errno));
4465 	return SANE_STATUS_IO_ERROR;
4466       }
4467 
4468     DBG (1, "sanei_scsi_cmd: status = %d\n", scsi_req.ds_status);
4469 
4470     /*
4471      * Set the incoming data size and copy the destination data as needed...
4472      */
4473     if (dst != NULL)
4474       {
4475 	*dst_size = scsi_req.ds_datasent;
4476 
4477 	DBG (1, "sanei_scsi_cmd: read %d bytes\n", scsi_req.ds_datasent);
4478 
4479 	if (scsi_req.ds_datasent > 0)
4480 	  memcpy (dst, databuf, scsi_req.ds_datasent);
4481       }
4482 
4483     /*
4484      * Return the appropriate status code...
4485      */
4486     if (scsi_req.ds_status != 0)
4487       {
4488 	if (scsi_req.ds_status == STA_BUSY)
4489 	  return SANE_STATUS_DEVICE_BUSY;
4490 	else if (fd_info[fd].sense_handler)
4491 	  return (*fd_info[fd].sense_handler) (fd, sensebuf,
4492 					       fd_info[fd].sense_handler_arg);
4493 	else
4494 	  return SANE_STATUS_IO_ERROR;
4495       }
4496     return SANE_STATUS_GOOD;
4497   }
4498 
4499   void
sanei_scsi_find_devices(const char * findvendor,const char * findmodel,const char * findtype,int findbus,int findchannel,int findid,int findlun,SANE_Status (* attach)(const char * dev))4500     sanei_scsi_find_devices (const char *findvendor, const char *findmodel,
4501 			     const char *findtype,
4502 			     int findbus, int findchannel, int findid,
4503 			     int findlun,
4504 			     SANE_Status (*attach) (const char *dev))
4505   {
4506     size_t findvendor_len = 0, findmodel_len = 0;
4507     /* Lengths of search strings */
4508     inventory_t *inv;		/* Current hardware inventory entry */
4509     int bus, id, lun;		/* Current Bus, ID, and LUN */
4510     char dev_name[128];		/* SCSI device name */
4511     int fd;			/* SCSI file */
4512     size_t inqsize;		/* Size of returned inquiry data */
4513     char vendor[9],		/* Vendor name */
4514       model[17];		/* Model/product name */
4515     u_char inqdata[128],	/* Inquiry data buffer */
4516       inqcommand[6];		/* Inquiry command (0x12) buffer */
4517 
4518     DBG_INIT ();
4519 
4520     vendor[0] = model[0] = '\0';
4521     if (findvendor)
4522       findvendor_len = strlen (findvendor);
4523     if (findmodel)
4524       findmodel_len = strlen (findmodel);
4525 
4526     if (findvendor != NULL)
4527       DBG (1, "sanei_scsi_find_devices: looking for vendors starting "
4528 	   "with \"%s\".\n", findvendor);
4529 
4530     if (findmodel != NULL)
4531       DBG (1, "sanei_scsi_find_devices: looking for models starting "
4532 	   "with \"%s\".\n", findmodel);
4533 
4534     setinvent ();
4535 
4536     while ((inv = getinvent ()) != NULL)
4537       {
4538 	if (inv->inv_class != INV_SCSI ||
4539 	    (inv->inv_type != INV_SCANNER && inv->inv_type != INV_CPU))
4540 	  continue;
4541 
4542 	bus = inv->inv_controller;
4543 	id = inv->inv_unit;
4544 	lun = inv->inv_state >> 8;
4545 
4546 	DBG (1, "sanei_scsi_find_devices: found %s on controller %d, "
4547 	     "ID %d, LUN %d.\n",
4548 	     inv->inv_type == INV_SCANNER ? "scanner" : "processor",
4549 	     bus, id, lun);
4550 
4551 	if ((findbus >= 0 && bus != findbus) ||
4552 	    (findid >= 0 && id != findid) || (findlun >= 0 && lun != findlun))
4553 	  {
4554 	    DBG (1, "sanei_scsi_find_devices: ignoring this device.\n");
4555 	    continue;
4556 	  }
4557 
4558 	sprintf (dev_name, "/dev/scsi/sc%dd%dl%d", bus, id, lun);
4559 	DBG (1, "sanei_scsi_find_devices: device name is \"%s\".\n",
4560 	     dev_name);
4561 
4562 	/*
4563 	 * Open the SCSI device and get the inquiry data...
4564 	 */
4565 
4566 	if (sanei_scsi_open (dev_name, &fd, NULL, NULL) != SANE_STATUS_GOOD)
4567 	  {
4568 	    DBG (1,
4569 		 "sanei_scsi_find_devices: unable to open device file - %s.\n",
4570 		 strerror (errno));
4571 	    continue;
4572 	  }
4573 
4574 	DBG (1, "sanei_scsi_find_devices: device fd = %d.\n", fd);
4575 
4576 	inqsize = sizeof (inqdata);
4577 
4578 	inqcommand[0] = 0x12;
4579 	inqcommand[1] = 0;
4580 	inqcommand[2] = 0;
4581 	inqcommand[3] = sizeof (inqdata) >> 8;
4582 	inqcommand[4] = sizeof (inqdata);
4583 	inqcommand[5] = 0;
4584 
4585 	if (sanei_scsi_cmd (fd, inqcommand, sizeof (inqcommand), inqdata,
4586 			    &inqsize) != SANE_STATUS_GOOD)
4587 	  {
4588 	    DBG (1,
4589 		 "sanei_scsi_find_devices: unable to get inquiry data - %s.\n",
4590 		 strerror (errno));
4591 	    continue;
4592 	  }
4593 
4594 	sanei_scsi_close (fd);
4595 
4596 	strncpy (vendor, (char *) inqdata + 8, 8);
4597 	vendor[8] = '\0';
4598 	strncpy (model, (char *) inqdata + 16, 16);
4599 	model[16] = '\0';
4600 
4601 	DBG (1, "sanei_scsi_find_devices: vendor = \'%s\', model = \'%s'.\n",
4602 	     vendor, model);
4603 
4604 	/*
4605 	 * Compare as necessary...
4606 	 */
4607 
4608 	if ((findvendor != NULL
4609 	     && strncmp (findvendor, vendor, findvendor_len))
4610 	    || (findmodel != NULL
4611 		&& strncmp (findmodel, model, findmodel_len)))
4612 	  {
4613 	    DBG (1, "sanei_scsi_find_devices: ignoring this device.\n");
4614 	    continue;
4615 	  }
4616 
4617 	/*
4618 	 * OK, this one matches, so use it!
4619 	 */
4620 
4621 	DBG (1, "sanei_scsi_find_devices: attaching this device.\n");
4622 
4623 	(*attach) (dev_name);
4624       }
4625   }
4626 #endif /* USE == IRIX_INTERFACE */
4627 
4628 #if USE == AIX_GSC_INTERFACE
4629   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)4630     sanei_scsi_cmd2 (int fd,
4631 		     const void *cmd, size_t cmd_size,
4632 		     const void *src, size_t src_size,
4633 		     void *dst, size_t * dst_size)
4634   {
4635     scmd_t scmd;
4636     /* xxx obsolete size_t cdb_size;
4637      */
4638     char sense_buf[32];
4639     char status;
4640 
4641     /* xxx obsolete cdb_size = CDB_SIZE (*(u_char *) src);
4642      */
4643 
4644     memset (&scmd, 0, sizeof (scmd));
4645     if (dst_size && *dst_size)
4646       {
4647 	/* xxx obsolete assert (cdb_size == src_size);
4648 	 */
4649 	scmd.rw = 1;
4650 	scmd.data_buf = dst;
4651 	scmd.datalen = *dst_size;
4652       }
4653     else
4654       {
4655 	/* assert (cdb_size <= src_size);
4656 	 */
4657 	scmd.data_buf = (char *) src;
4658 	scmd.datalen = src_size;
4659       }
4660     scmd.cdb = (char *) cmd;
4661     scmd.cdblen = cmd_size;
4662     scmd.timeval = sane_scsicmd_timeout;
4663     scmd.sense_buf = sense_buf;
4664     scmd.senselen = sizeof (sense_buf);
4665     scmd.statusp = &status;
4666     DBG (1, "sanei_scsi_cmd: scmd.rw = %d, scmd.cdblen = %d, ",
4667 	 scmd.rw, scmd.cdblen);
4668     DBG (1, "scmd.cdb = {0x%x,0x%x,0x%x,0x%x,0x%x,0x%x, ...}\n",
4669 	 scmd.cdb[0], scmd.cdb[1], scmd.cdb[2],
4670 	 scmd.cdb[3], scmd.cdb[4], scmd.cdb[5]);
4671     if (ioctl (fd, GSC_CMD, &scmd) < 0)
4672       {
4673 	DBG (1, "sanei_scsi_cmd: ioctl(SIOC_IO) failed: %s\n",
4674 	     strerror (errno));
4675 	return SANE_STATUS_IO_ERROR;
4676       }
4677     if (*scmd.statusp)
4678       DBG (1, "sanei_scsi_cmd: SCSI completed with status=%d\n",
4679 	   *scmd.statusp);
4680 
4681     DBG (1, "sanei_scsi_cmd: dst = {0x%x,0x%x,0x%x,0x%x,0x%x,0x%x, ...}\n",
4682 	 *((char *) dst + 0), *((char *) dst + 1), *((char *) dst + 2),
4683 	 *((char *) dst + 3), *((char *) dst + 4), *((char *) dst + 5));
4684 
4685     if (dst_size)
4686       *dst_size = scmd.datalen;
4687 
4688     if (scmd.senselen > 0
4689 	&& (scmd.sense_buf[0] & 0x80) && fd_info[fd].sense_handler)
4690       return (*fd_info[fd].sense_handler) (fd, (u_char *) scmd.sense_buf,
4691 					   fd_info[fd].sense_handler_arg);
4692     return SANE_STATUS_GOOD;
4693   }
4694 #endif /* USE == AIX_GSC_INTERFACE */
4695 
4696 #if USE == SOLARIS_SG_INTERFACE
4697 
4698 #ifndef CCS_SENSE_LEN
4699 # define CCS_SENSE_LEN 18
4700 #endif
4701 
4702   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)4703     sanei_scsi_cmd2 (int fd,
4704 		     const void *cmd, size_t cmd_size,
4705 		     const void *src, size_t src_size,
4706 		     void *dst, size_t * dst_size)
4707   {
4708     struct user_scsi us;
4709     /* xxx obsolete size_t cdb_size;
4710      */
4711     char sensebf[CCS_SENSE_LEN];
4712 
4713     /* xxx obsolete cdb_size = CDB_SIZE (*(u_char *) src);
4714      */
4715 
4716     /* first put the user scsi structure together.  */
4717     memset (&us, 0, sizeof (us));
4718     us.us_cdbp = (caddr_t) cmd;
4719     us.us_cdblen = cmd_size;
4720     us.us_sensep = sensebf;
4721     us.us_senselen = CCS_SENSE_LEN;
4722     if (dst && dst_size && *dst_size)
4723       {
4724 	us.us_bufp = (caddr_t) dst;
4725 	us.us_buflen = *dst_size;
4726 	us.us_flags = USER_SCSI_READ;
4727       }
4728     else
4729       {
4730 	us.us_bufp = (caddr_t) src;
4731 	us.us_buflen = src_size;
4732 	us.us_flags = USER_SCSI_WRITE;
4733       }
4734     /* now run it */
4735     if (ioctl (fd, USER_SCSI, &us) < 0)
4736       return SANE_STATUS_IO_ERROR;
4737     if (dst_size)
4738       *dst_size -= us.us_resid;
4739 
4740     return SANE_STATUS_GOOD;
4741   }
4742 #endif /* USE == SOLARIS_SG_INTERFACE */
4743 
4744 #if USE == SOLARIS_INTERFACE
4745 
4746 #ifndef SC_NOT_READ
4747 # define SC_NOT_READY		0x02
4748 #endif
4749 
4750 #ifndef SC_BUSY
4751 # define SC_BUSY		0x08
4752 #endif
4753 #define DEF_TIMEOUT sane_scsicmd_timeout;
4754 
4755 /* Choosing one of the following DEF_SCG_FLG's SCG_DISRE_ENA allows
4756    the SCSI driver to disconnect/reconnect.  SCG_CMD_RETRY allows a
4757    retry if a retryable error occurs.
4758 
4759    Disallowing SCG_DISRE_ENA slows down the operation of the SCSI bus
4760    while the scanner is working. If you have severe problems try to
4761    set it to 0.
4762 
4763    SCG_CMD_RETRY allows the driver to retry some commands.  It should
4764    normally be set.  For some kinds of odd problems, it may cause the
4765    machine to hang for some time.  */
4766 
4767 #define DEF_SCG_FLG	SCG_DISRE_ENA
4768 /* #define DEF_SCG_FLG  0                               */
4769 /* #define DEF_SCG_FLG  SCG_DISRE_ENA | SCG_CMD_RETRY   */
4770 /* #define DEF_SCG_FLG  SCG_CMD_RETRY                   */
4771 
4772   static int d_errs = 100;
4773 
4774   static SANE_Status
scsi_cmd(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size,int probing)4775     scsi_cmd (int fd,
4776 	      const void *cmd, size_t cmd_size,
4777 	      const void *src, size_t src_size,
4778 	      void *dst, size_t * dst_size, int probing)
4779   {
4780     struct scg_cmd scmd;
4781     /* xxx obsolete size_t cdb_size;
4782      */
4783     SANEI_SCSI_Sense_Handler handler;
4784 
4785     /* xxx obsolete cdb_size = CDB_SIZE (*(u_char *) src);
4786      */
4787 
4788     memset (&scmd, 0, sizeof (scmd));
4789     scmd.flags = DEF_SCG_FLG | (probing ? SCG_SILENT : 0);
4790     if (dst && dst_size && *dst_size)
4791       {
4792 	/* xxx obsolete assert (cdb_size == src_size);
4793 	 */
4794 	scmd.flags |= SCG_RECV_DATA;
4795 	scmd.addr = dst;
4796 	scmd.size = *dst_size;
4797       }
4798     else
4799       {
4800 	/* xxx obsolete assert (cdb_size <= src_size);
4801 	 */
4802 	scmd.addr = (caddr_t) src;
4803 	scmd.size = src_size;
4804       }
4805     scmd.cdb_len = cmd_size;
4806     scmd.sense_len = CCS_SENSE_LEN;
4807     scmd.target = fd_info[fd].target;
4808     /* use 2 second timeout when probing, 60 seconds otherwise: */
4809     scmd.timeout = probing ? 2 : DEF_TIMEOUT;
4810     memcpy (&scmd.cdb.g0_cdb.cmd, cmd, cmd_size);
4811     scmd.cdb.cmd_cdb[1] |= fd_info[fd].lun << 5;
4812     if (ioctl (fd, SCGIO_CMD, &scmd) < 0)
4813       return SANE_STATUS_IO_ERROR;
4814     if (dst_size)
4815       *dst_size = scmd.size - scmd.resid;
4816     if (scmd.error == 0 && scmd.errno == 0 && *(u_char *) & scmd.scb == 0)
4817       return SANE_STATUS_GOOD;
4818 
4819     if (scmd.error == SCG_TIMEOUT)
4820       DBG (0, "sanei_scsi_cmd %x: timeout\n", scmd.cdb.g0_cdb.cmd);
4821     else if (probing)
4822       {
4823 	struct scsi_ext_sense *ext_sense =
4824 	  (struct scsi_ext_sense *) &scmd.sense;
4825 
4826 	if (scmd.error < SCG_FATAL
4827 	    && ((scmd.sense.code < 0x70 && scmd.sense.code != 0x04)
4828 		|| (scmd.sense.code >= 0x70
4829 		    && ext_sense->key != SC_NOT_READY)))
4830 	  return SANE_STATUS_GOOD;
4831       }
4832     else
4833       {
4834 	char errbf[128];
4835 	int i, rv, lifes;
4836 
4837 	handler = fd_info[fd].sense_handler;
4838 	DBG (3, "cmd=%x, error=%d:%s, bsiz=%d, stat=%x,%x,%x, slen=%d\n",
4839 	     scmd.cdb.g0_cdb.cmd, scmd.error, strerror (scmd.errno),
4840 	     ((dst_size != NULL) ? (*dst_size) : 0), scmd.u_scb.cmd_scb[0],
4841 	     scmd.u_scb.cmd_scb[1], scmd.u_scb.cmd_scb[2], scmd.sense_count);
4842 	*errbf = '\0';
4843 	for (i = 0; i < scmd.sense_count; i++)
4844 	  sprintf (errbf + strlen (errbf), "%x,", scmd.u_sense.cmd_sense[i]);
4845 	DBG (3, "sense=%s\n", errbf);
4846 
4847 	/* test_unit_ready on a busy unit returns error = 0 or 2 with
4848 	   errno=EIO.  I've seen 0 on a CDrom without a CD, and 2 on a
4849 	   scanner just busy.
4850 
4851 	   If (SANE_DEBUG_SANEI_SCSI > 100) lifes =
4852 	   SANE_DEBUG_SANEI_SCSI - 100 use up one life for every
4853 	   scmd.error abort and dump core when no lifes left
4854 	   test_unit_ready commands are not counted.  */
4855 	if (scmd.error)
4856 	  {
4857 	    if (sanei_debug_sanei_scsi > 100 &&
4858 		scmd.cdb.g0_cdb.cmd != SC_TEST_UNIT_READY)
4859 	      {
4860 		lifes = sanei_debug_sanei_scsi - ++d_errs;
4861 		DBG (1, "sanei_scsi_cmd: %d lifes left\n", lifes);
4862 		assert (lifes > 0);
4863 	      }
4864 	    return SANE_STATUS_IO_ERROR;
4865 	  }
4866 	if (scmd.u_scb.cmd_scb[0] == SC_BUSY)
4867 	  return SANE_STATUS_DEVICE_BUSY;
4868 	if (*(u_char *) & scmd.sense && handler)
4869 	  {
4870 	    rv = (*handler) (fd, scmd.u_sense.cmd_sense,
4871 			     fd_info[fd].sense_handler_arg);
4872 	    DBG (2, "sanei_scsi_cmd: sense-handler returns %d\n", rv);
4873 	    return rv;
4874 	  }
4875       }
4876     return SANE_STATUS_IO_ERROR;
4877   }
4878 
4879   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)4880     sanei_scsi_cmd2 (int fd,
4881 		     const void *cmd, size_t cmd_size,
4882 		     const void *src, size_t src_size,
4883 		     void *dst, size_t * dst_size)
4884   {
4885     return scsi_cmd (fd, cmd, cmd_size, src, src_size, dst, dst_size, 0);
4886   }
4887 
unit_ready(int fd)4888   static int unit_ready (int fd)
4889   {
4890     static const u_char test_unit_ready[] = { 0, 0, 0, 0, 0, 0 };
4891     int status;
4892 
4893     status = scsi_cmd (fd, test_unit_ready, sizeof (test_unit_ready),
4894 		       0, 0, 0, 0, 1);
4895     return (status == SANE_STATUS_GOOD);
4896   }
4897 
4898 #endif /* USE == SOLARIS_INTERFACE */
4899 
4900 
4901 #if USE == SOLARIS_USCSI_INTERFACE
4902 
4903 #define DEF_TIMEOUT sane_scsicmd_timeout;
4904 
4905   static int d_errs = 100;
4906   typedef struct scsi_extended_sense extended_sense_t;
4907   typedef struct scsi_inquiry scsi_inquiry_t;
4908 
4909   static SANE_Status
scsi_cmd(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size,int probing)4910     scsi_cmd (int fd,
4911 	      const void *cmd, size_t cmd_size,
4912 	      const void *src, size_t src_size,
4913 	      void *dst, size_t * dst_size, int probing)
4914   {
4915     struct uscsi_cmd us;
4916     scsi_inquiry_t inquiry, *iq = &inquiry;
4917     extended_sense_t sense, *sp = &sense;
4918     SANEI_SCSI_Sense_Handler handler;
4919 
4920     memset (&us, 0, sizeof (us));
4921     memset (sp, 0, sizeof (*sp));
4922 
4923     us.uscsi_flags = USCSI_SILENT | USCSI_RQENABLE | USCSI_DIAGNOSE;
4924     us.uscsi_timeout = probing ? 2 : DEF_TIMEOUT;
4925     us.uscsi_rqbuf = (caddr_t) sp;	/* sense data address */
4926     us.uscsi_rqlen = sizeof (extended_sense_t);	/* length of sense data */
4927 
4928     if (dst && dst_size && *dst_size)
4929       {
4930 	us.uscsi_flags |= USCSI_READ;
4931 	us.uscsi_bufaddr = (caddr_t) dst;
4932 	us.uscsi_buflen = *dst_size;
4933       }
4934     else
4935       {
4936 	us.uscsi_flags |= USCSI_WRITE;
4937 	us.uscsi_bufaddr = (caddr_t) src;
4938 	us.uscsi_buflen = src_size;
4939       }
4940 
4941     us.uscsi_cdblen = cmd_size;
4942     us.uscsi_cdb = (caddr_t) cmd;
4943 
4944     if (ioctl (fd, USCSICMD, &us) < 0)
4945       return SANE_STATUS_IO_ERROR;
4946 
4947     if (dst_size)
4948       *dst_size = us.uscsi_buflen - us.uscsi_resid;
4949 
4950     if ((us.uscsi_status & STATUS_MASK) == STATUS_GOOD)
4951       return SANE_STATUS_GOOD;
4952 
4953     if (sp->es_key == SUN_KEY_TIMEOUT)
4954       DBG (0, "sanei_scsi_cmd %x: timeout\n", *(char *) cmd);
4955     else
4956       {
4957 	char errbf[128];
4958 	int i, rv, lifes;
4959 
4960 	handler = fd_info[fd].sense_handler;
4961 	DBG (3, "cmd=%x, scsi_status=%x\n", *(char *) cmd, us.uscsi_status);
4962 	*errbf = '\0';
4963 
4964 	for (i = 0; i < us.uscsi_rqlen; i++)
4965 	  sprintf (errbf + strlen (errbf), "%x,", *(sp + i));
4966 
4967 	DBG (3, "sense=%s\n", errbf);
4968 
4969 #if 0
4970 	if (us.error)
4971 	  {
4972 	    if (sanei_debug_sanei_scsi > 100 &&
4973 		scmd.cdb.g0_cdb.cmd != SC_TEST_UNIT_READY)
4974 	      {
4975 		lifes = sanei_debug_sanei_scsi - ++d_errs;
4976 		DBG (1, "sanei_scsi_cmd: %d lifes left\n", lifes);
4977 		assert (lifes > 0);
4978 	      }
4979 	    return SANE_STATUS_IO_ERROR;
4980 	  }
4981 
4982 	if (scmd.u_scb.cmd_scb[0] == SC_BUSY)
4983 	  return SANE_STATUS_DEVICE_BUSY;
4984 #endif
4985 
4986 	if (handler)
4987 	  {
4988 	    rv = (*handler) (fd, (unsigned char *) sp,
4989 			     fd_info[fd].sense_handler_arg);
4990 	    DBG (2, "sanei_scsi_cmd: sense-handler returns %d\n", rv);
4991 	    return rv;
4992 	  }
4993       }
4994 
4995     return SANE_STATUS_IO_ERROR;
4996   }
4997 
4998   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)4999     sanei_scsi_cmd2 (int fd,
5000 		     const void *cmd, size_t cmd_size,
5001 		     const void *src, size_t src_size,
5002 		     void *dst, size_t * dst_size)
5003   {
5004     return scsi_cmd (fd, cmd, cmd_size, src, src_size, dst, dst_size, 0);
5005   }
5006 
unit_ready(int fd)5007   static int unit_ready (int fd)
5008   {
5009     static const u_char test_unit_ready[] = { 0, 0, 0, 0, 0, 0 };
5010     int status;
5011 
5012     status = scsi_cmd (fd, test_unit_ready, sizeof (test_unit_ready),
5013 		       0, 0, 0, 0, 1);
5014     return (status == SANE_STATUS_GOOD);
5015   }
5016 #endif /* USE == SOLARIS_USCSI_INTERFACE */
5017 
5018 #if USE == WIN32_INTERFACE
5019 
5020 SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)5021 sanei_scsi_cmd2 (int fd,
5022                 const void *cmd, size_t cmd_size,
5023                 const void *src, size_t src_size,
5024 		void *dst, size_t * dst_size)
5025 {
5026   struct pkt {
5027     SCSI_PASS_THROUGH_DIRECT sptd;
5028     unsigned char sense[255];
5029   } pkt;
5030   DWORD BytesReturned;
5031   BOOL ret;
5032 
5033   memset(&pkt, 0, sizeof( pkt ));
5034   pkt.sptd.Length = sizeof( SCSI_PASS_THROUGH_DIRECT );
5035 
5036   pkt.sptd.PathId = fd_info[fd].bus;
5037   pkt.sptd.TargetId = fd_info[fd].target;
5038   pkt.sptd.Lun = fd_info[fd].lun;
5039 
5040   assert(cmd_size == 6 || cmd_size == 10 || cmd_size == 12 || cmd_size == 16);
5041   memcpy(pkt.sptd.Cdb, cmd, cmd_size);
5042   pkt.sptd.CdbLength = cmd_size;
5043 
5044   if (dst_size && *dst_size)
5045     {
5046 	pkt.sptd.DataIn = SCSI_IOCTL_DATA_IN;
5047 	pkt.sptd.DataTransferLength = *dst_size;
5048         pkt.sptd.DataBuffer         = dst;
5049     }
5050   else if (src_size)
5051     {
5052 	pkt.sptd.DataIn = SCSI_IOCTL_DATA_OUT;
5053 	pkt.sptd.DataTransferLength = src_size;
5054         pkt.sptd.DataBuffer         = src;
5055     }
5056   else {
5057        pkt.sptd.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
5058   }
5059 
5060   pkt.sptd.TimeOutValue       = sane_scsicmd_timeout;
5061 
5062   pkt.sptd.SenseInfoOffset = (void *)pkt.sense - (void *)&pkt;
5063   pkt.sptd.SenseInfoLength = sizeof(pkt.sense);
5064 
5065   ret = DeviceIoControl(fd,
5066                         IOCTL_SCSI_PASS_THROUGH_DIRECT,
5067                         &pkt.sptd, sizeof( pkt ),
5068                         &pkt.sptd, sizeof( pkt ),
5069                         &BytesReturned, NULL );
5070 
5071   if (ret == 0)
5072     {
5073       DBG (1, "sanei_scsi_cmd2: DeviceIoControl() failed: %ld\n",
5074 	   GetLastError());
5075       return SANE_STATUS_IO_ERROR;
5076     }
5077 
5078    if (pkt.sptd.ScsiStatus == 2){
5079 	/* Check condition. */
5080       SANEI_SCSI_Sense_Handler handler;
5081 
5082       handler = fd_info[fd].sense_handler;
5083       if (handler) {
5084 	 return handler(fd, pkt.sense, fd_info[fd].sense_handler_arg);
5085       }
5086       else {
5087 	 return SANE_STATUS_IO_ERROR;
5088       }
5089    }
5090    else if (pkt.sptd.ScsiStatus != 0) {
5091       DBG (1, "sanei_scsi_cmd2: ScsiStatus is %d\n",
5092 	    pkt.sptd.ScsiStatus);
5093       return SANE_STATUS_IO_ERROR;
5094    }
5095 
5096   if (dst_size) {
5097     *dst_size = pkt.sptd.DataTransferLength;
5098   }
5099 
5100   return SANE_STATUS_GOOD;
5101 }
5102 
5103 #define WE_HAVE_FIND_DEVICES
5104 
5105 /* This is almost the same algorithm used in sane-find-scanner. */
5106 void
sanei_scsi_find_devices(const char * findvendor,const char * findmodel,const char * findtype,int findbus,int findchannel,int findid,int findlun,SANE_Status (* attach)(const char * dev))5107 sanei_scsi_find_devices (const char *findvendor, const char *findmodel,
5108 			 const char *findtype,
5109 			 int findbus, int findchannel, int findid, int findlun,
5110 			 SANE_Status (*attach) (const char *dev))
5111 {
5112 	int hca;
5113 	HANDLE fd;
5114 	char scsi_hca_name[20];
5115 	char buffer[4096];
5116 	DWORD BytesReturned;
5117 	BOOL ret;
5118 	PSCSI_ADAPTER_BUS_INFO adapter;
5119 	PSCSI_INQUIRY_DATA inquiry;
5120 	int i;
5121 
5122 	DBG_INIT();
5123 
5124 	hca = 0;
5125 
5126 	for(hca = 0; ; hca++) {
5127 
5128 	/* Open the adapter */
5129 	snprintf(scsi_hca_name, 20, "\\\\.\\Scsi%d:", hca);
5130 	fd = CreateFile(scsi_hca_name, GENERIC_READ | GENERIC_WRITE,
5131                                FILE_SHARE_READ | FILE_SHARE_WRITE,
5132                                NULL, OPEN_EXISTING,
5133                                FILE_FLAG_RANDOM_ACCESS, NULL );
5134 
5135 	if (fd == INVALID_HANDLE_VALUE) {
5136 	   /* Assume there is no more adapter. This is wrong in the case
5137 	   * of hot-plug stuff, but I have yet to see it on a user
5138 	   * machine. */
5139 	   break;
5140 	}
5141 
5142 	/* Get the inquiry info for the devices on that hca. */
5143         ret = DeviceIoControl(fd,
5144                                  IOCTL_SCSI_GET_INQUIRY_DATA,
5145                                  NULL,
5146                                  0,
5147                                  buffer,
5148                                  sizeof(buffer),
5149                                  &BytesReturned,
5150                                  FALSE);
5151 
5152         if(ret == 0)
5153         {
5154 	CloseHandle(fd);
5155             continue;
5156         }
5157 
5158 	adapter = (PSCSI_ADAPTER_BUS_INFO)buffer;
5159 
5160 	for(i = 0; i < adapter->NumberOfBuses; i++) {
5161 
5162 		if (adapter->BusData[i].InquiryDataOffset == 0) {
5163 			/* No device here */
5164 			continue;
5165 		}
5166 
5167 		inquiry = (PSCSI_INQUIRY_DATA) (buffer +
5168                                    adapter->BusData[i].InquiryDataOffset);
5169 
5170 		while(1) {
5171 
5172 			if ((findvendor == NULL || strncmp(findvendor, (char *)&inquiry->InquiryData[8], 8) == 0)) {
5173 				DBG(1, "OK1\n");
5174 			} else {
5175 				DBG(1, "failed for [%s] and [%s]\n",findvendor, (char *)&inquiry->InquiryData[8] );
5176 			}
5177 
5178 
5179 			/* Check if this device fits the criteria. */
5180 			if ((findvendor == NULL || strncmp(findvendor, (char *)&inquiry->InquiryData[8], strlen(findvendor)) == 0) &&
5181 			    (findmodel == NULL || strncmp(findmodel, (char *)&inquiry->InquiryData[16], strlen(findmodel)) == 0) &&
5182 			    (findbus == -1 || findbus == hca) &&
5183 			    (findchannel == -1 || findchannel == inquiry->PathId) &&
5184 			    (findid == -1 || findid == inquiry->TargetId) &&
5185 			    (findlun == -1 || findlun == inquiry->Lun)) {
5186 
5187 				char device_name[20];
5188 				sprintf(device_name, "h%db%dt%dl%d", hca, inquiry->PathId, inquiry->TargetId, inquiry->Lun);
5189 				attach(device_name);
5190 			}
5191 			if (inquiry->NextInquiryDataOffset == 0) {
5192 			   /* No device here */
5193 			   break;
5194 			} else {
5195 			   inquiry =  (PSCSI_INQUIRY_DATA) (buffer +
5196                           inquiry->NextInquiryDataOffset);
5197 			}
5198 		}
5199 	    }
5200 	CloseHandle(fd);
5201 
5202         }
5203 }
5204 #endif /* USE == WIN32_INTERFACE */
5205 
5206 #if USE == MACOSX_INTERFACE
5207 
5208 # ifdef HAVE_IOKIT_CDB_IOSCSILIB_H
5209 
5210   static SANE_Status
sanei_scsi_cmd2_old_api(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)5211     sanei_scsi_cmd2_old_api (int fd,
5212 			     const void *cmd, size_t cmd_size,
5213 			     const void *src, size_t src_size,
5214 			     void *dst, size_t * dst_size)
5215   {
5216     mach_port_t masterPort;
5217     IOReturn ioReturnValue;
5218     io_object_t scsiDevice;
5219     int i;
5220     CFMutableDictionaryRef scsiMatchDictionary;
5221     int deviceTypeNumber;
5222     CFNumberRef deviceTypeRef;
5223     io_iterator_t scsiObjectIterator;
5224     io_object_t device;
5225     CFNumberRef IOUnitRef;
5226     int iounit;
5227     CFNumberRef scsiTargetRef;
5228     int scsitarget;
5229     CFNumberRef scsiLunRef;
5230     int scsilun;
5231     IOCFPlugInInterface **plugInInterface;
5232     SInt32 score;
5233     HRESULT plugInResult;
5234     IOSCSIDeviceInterface **scsiDeviceInterface;
5235     IOCDBCommandInterface **cdbCommandInterface;
5236     CDBInfo cdb;
5237     IOVirtualRange range;
5238     UInt32 transferCount;
5239     Boolean isWrite;
5240     SCSIResults results;
5241     UInt32 seqNumber;
5242 
5243     masterPort = 0;
5244     ioReturnValue = IOMasterPort (MACH_PORT_NULL, &masterPort);
5245     if (ioReturnValue != kIOReturnSuccess || masterPort == 0)
5246       {
5247 	DBG (5, "Could not get I/O master port (0x%08x)\n", ioReturnValue);
5248 	return SANE_STATUS_IO_ERROR;
5249       }
5250 
5251     scsiDevice = 0;
5252     for (i = 0; !scsiDevice && i < 2; i++)
5253       {
5254 	scsiMatchDictionary = IOServiceMatching (kIOSCSIDeviceClassName);
5255 	if (scsiMatchDictionary == NULL)
5256 	  {
5257 	    DBG (5, "Could not create SCSI matching dictionary\n");
5258 	    return SANE_STATUS_NO_MEM;
5259 	  }
5260 
5261 	deviceTypeNumber =
5262 	  (i == 0 ? kSCSIDevTypeScanner : kSCSIDevTypeProcessor);
5263 	deviceTypeRef = CFNumberCreate (NULL, kCFNumberIntType,
5264 					&deviceTypeNumber);
5265 	CFDictionarySetValue (scsiMatchDictionary,
5266 			      CFSTR (kSCSIPropertyDeviceTypeID),
5267 			      deviceTypeRef);
5268 	CFRelease (deviceTypeRef);
5269 
5270 	scsiObjectIterator = 0;
5271 	ioReturnValue = IOServiceGetMatchingServices (masterPort,
5272 						      scsiMatchDictionary,
5273 						      &scsiObjectIterator);
5274 	if (ioReturnValue != kIOReturnSuccess)
5275 	  {
5276 	    DBG (5, "Could not match services (0x%08x)\n", ioReturnValue);
5277 	    return SANE_STATUS_NO_MEM;
5278 	  }
5279 
5280 	while ((device = IOIteratorNext (scsiObjectIterator)))
5281 	  {
5282 	    IOUnitRef =
5283 	      IORegistryEntryCreateCFProperty (device,
5284 					       CFSTR (kSCSIPropertyIOUnit),
5285 					       NULL, 0);
5286 	    CFNumberGetValue (IOUnitRef, kCFNumberIntType, &iounit);
5287 	    CFRelease (IOUnitRef);
5288 	    scsiTargetRef =
5289 	      IORegistryEntryCreateCFProperty (device,
5290 					       CFSTR (kSCSIPropertyTarget),
5291 					       NULL, 0);
5292 	    CFNumberGetValue (scsiTargetRef, kCFNumberIntType, &scsitarget);
5293 	    CFRelease (scsiTargetRef);
5294 	    scsiLunRef =
5295 	      IORegistryEntryCreateCFProperty (device,
5296 					       CFSTR (kSCSIPropertyLun),
5297 					       NULL, 0);
5298 	    CFNumberGetValue (scsiLunRef, kCFNumberIntType, &scsilun);
5299 	    CFRelease (scsiLunRef);
5300 
5301 	    if (fd_info[fd].bus == iounit &&
5302 		fd_info[fd].target == scsitarget &&
5303 		fd_info[fd].lun == scsilun)
5304 	      scsiDevice = device;
5305 	    else
5306 	      IOObjectRelease (device);
5307 	  }
5308 	IOObjectRelease (scsiObjectIterator);
5309       }
5310     if (!scsiDevice)
5311       {
5312 	DBG (5, "Device not found (unit %i, target %i, lun %i)\n",
5313 	     fd_info[fd].bus, fd_info[fd].target, fd_info[fd].lun);
5314 	return SANE_STATUS_INVAL;
5315       }
5316 
5317     plugInInterface = NULL;
5318     score = 0;
5319     ioReturnValue = IOCreatePlugInInterfaceForService (scsiDevice,
5320 						       kIOSCSIUserClientTypeID,
5321 						       kIOCFPlugInInterfaceID,
5322 						       &plugInInterface,
5323 						       &score);
5324     if (ioReturnValue != kIOReturnSuccess || plugInInterface == NULL)
5325       {
5326 	DBG (5, "Error creating plugin interface (0x%08x)\n", ioReturnValue);
5327 	return SANE_STATUS_NO_MEM;
5328       }
5329 
5330     scsiDeviceInterface = NULL;
5331     plugInResult = (*plugInInterface)->
5332       QueryInterface (plugInInterface,
5333 		      CFUUIDGetUUIDBytes (kIOSCSIDeviceInterfaceID),
5334 		      (LPVOID) & scsiDeviceInterface);
5335     if (plugInResult != S_OK || scsiDeviceInterface == NULL)
5336       {
5337 	DBG (5, "Couldn't create SCSI device interface (%ld)\n", plugInResult);
5338 	return SANE_STATUS_NO_MEM;
5339       }
5340 
5341     (*plugInInterface)->Release (plugInInterface);
5342     IOObjectRelease (scsiDevice);
5343 
5344     ioReturnValue = (*scsiDeviceInterface)->open (scsiDeviceInterface);
5345     if (ioReturnValue != kIOReturnSuccess)
5346       {
5347 	DBG (5, "Error opening SCSI interface (0x%08x)\n", ioReturnValue);
5348 	return SANE_STATUS_IO_ERROR;
5349       }
5350 
5351     cdbCommandInterface = NULL;
5352     plugInResult = (*scsiDeviceInterface)->
5353       QueryInterface (scsiDeviceInterface,
5354 		      CFUUIDGetUUIDBytes (kIOCDBCommandInterfaceID),
5355 		      (LPVOID) & cdbCommandInterface);
5356     if (plugInResult != S_OK || cdbCommandInterface == NULL)
5357       {
5358 	DBG (5, "Error creating CDB interface (%ld)\n", plugInResult);
5359 	return SANE_STATUS_NO_MEM;
5360       }
5361 
5362     cdb.cdbLength = cmd_size;
5363     memcpy (&cdb.cdb, cmd, cmd_size);
5364     if (dst && dst_size)
5365       {
5366 	memset (dst, 0, *dst_size);
5367 	range.address = (IOVirtualAddress) dst;
5368 	range.length = *dst_size;
5369 	transferCount = *dst_size;
5370 	isWrite = false;
5371       }
5372     else
5373       {
5374 	range.address = (IOVirtualAddress) src;
5375 	range.length = src_size;
5376 	transferCount = src_size;
5377 	isWrite = true;
5378       }
5379 
5380     seqNumber = 0;
5381     ioReturnValue = (*cdbCommandInterface)->
5382       setAndExecuteCommand (cdbCommandInterface, &cdb, transferCount,
5383 			    &range, 1, isWrite, sane_scsicmd_timeout * 1000,
5384 			    0, 0, 0, &seqNumber);
5385     if (ioReturnValue != kIOReturnSuccess &&
5386 	ioReturnValue != kIOReturnUnderrun)
5387       {
5388 	DBG (5, "Error executing CDB command (0x%08x)\n", ioReturnValue);
5389 	return SANE_STATUS_IO_ERROR;
5390       }
5391 
5392     ioReturnValue = (*cdbCommandInterface)->getResults (cdbCommandInterface,
5393 							&results);
5394     if (ioReturnValue != kIOReturnSuccess &&
5395 	ioReturnValue != kIOReturnUnderrun)
5396       {
5397 	DBG (5, "Error getting results from CDB Interface (0x%08x)\n",
5398 	     ioReturnValue);
5399 	return SANE_STATUS_IO_ERROR;
5400       }
5401 
5402     if (dst && dst_size)
5403       *dst_size = results.bytesTransferred;
5404 
5405     (*cdbCommandInterface)->Release (cdbCommandInterface);
5406     (*scsiDeviceInterface)->close (scsiDeviceInterface);
5407     (*scsiDeviceInterface)->Release (scsiDeviceInterface);
5408 
5409     return SANE_STATUS_GOOD;
5410   }
5411 
5412 
5413   static void
sanei_scsi_find_devices_old_api(const char * findvendor,const char * findmodel,const char * findtype,int findbus,int findchannel,int findid,int findlun,SANE_Status (* attach)(const char * dev))5414     sanei_scsi_find_devices_old_api (const char *findvendor,
5415 				     const char *findmodel,
5416 				     const char *findtype, int findbus,
5417 				     int findchannel, int findid, int findlun,
5418 				     SANE_Status (*attach) (const char *dev))
5419   {
5420     mach_port_t masterPort;
5421     IOReturn ioReturnValue;
5422     int i;
5423     CFMutableDictionaryRef scsiMatchDictionary;
5424     int deviceTypeNumber;
5425     CFNumberRef deviceTypeRef;
5426     io_iterator_t scsiObjectIterator;
5427     io_object_t scsiDevice;
5428     CFNumberRef IOUnitRef;
5429     int iounit;
5430     CFNumberRef scsiTargetRef;
5431     int scsitarget;
5432     CFNumberRef scsiLunRef;
5433     int scsilun;
5434     IOCFPlugInInterface **plugInInterface;
5435     SInt32 score;
5436     HRESULT plugInResult;
5437     IOSCSIDeviceInterface **scsiDeviceInterface;
5438     SCSIInquiry inquiry;
5439     UInt32 inquirySize;
5440     char devname[16];
5441 
5442     masterPort = 0;
5443     ioReturnValue = IOMasterPort (MACH_PORT_NULL, &masterPort);
5444     if (ioReturnValue != kIOReturnSuccess || masterPort == 0)
5445       {
5446 	DBG (5, "Could not get I/O master port (0x%08x)\n", ioReturnValue);
5447 	return;
5448       }
5449 
5450     for (i = 0; i < 2; i++)
5451       {
5452 	scsiMatchDictionary = IOServiceMatching (kIOSCSIDeviceClassName);
5453 	if (scsiMatchDictionary == NULL)
5454 	  {
5455 	    DBG (5, "Could not create SCSI matching dictionary\n");
5456 	    return;
5457 	  }
5458 	deviceTypeNumber =
5459 	  (i == 0 ? kSCSIDevTypeScanner : kSCSIDevTypeProcessor);
5460 	deviceTypeRef = CFNumberCreate (NULL, kCFNumberIntType,
5461 					&deviceTypeNumber);
5462 	CFDictionarySetValue (scsiMatchDictionary,
5463 			      CFSTR (kSCSIPropertyDeviceTypeID),
5464 			      deviceTypeRef);
5465 	CFRelease (deviceTypeRef);
5466 
5467 	scsiObjectIterator = 0;
5468 	ioReturnValue = IOServiceGetMatchingServices (masterPort,
5469 						      scsiMatchDictionary,
5470 						      &scsiObjectIterator);
5471 	if (ioReturnValue != kIOReturnSuccess)
5472 	  {
5473 	    DBG (5, "Could not match services (0x%08x)\n", ioReturnValue);
5474 	    return;
5475 	  }
5476 
5477 	while ((scsiDevice = IOIteratorNext (scsiObjectIterator)))
5478 	  {
5479 	    IOUnitRef =
5480 	      IORegistryEntryCreateCFProperty (scsiDevice,
5481 					       CFSTR (kSCSIPropertyIOUnit),
5482 					       NULL, 0);
5483 	    CFNumberGetValue (IOUnitRef, kCFNumberIntType, &iounit);
5484 	    CFRelease (IOUnitRef);
5485 	    scsiTargetRef =
5486 	      IORegistryEntryCreateCFProperty (scsiDevice,
5487 					       CFSTR (kSCSIPropertyTarget),
5488 					       NULL, 0);
5489 	    CFNumberGetValue (scsiTargetRef, kCFNumberIntType, &scsitarget);
5490 	    CFRelease (scsiTargetRef);
5491 	    scsiLunRef =
5492 	      IORegistryEntryCreateCFProperty (scsiDevice,
5493 					       CFSTR (kSCSIPropertyLun),
5494 					       NULL, 0);
5495 	    CFNumberGetValue (scsiLunRef, kCFNumberIntType, &scsilun);
5496 	    CFRelease (scsiLunRef);
5497 
5498 	    plugInInterface = NULL;
5499 	    score = 0;
5500 	    ioReturnValue =
5501 	      IOCreatePlugInInterfaceForService (scsiDevice,
5502 						 kIOSCSIUserClientTypeID,
5503 						 kIOCFPlugInInterfaceID,
5504 						 &plugInInterface, &score);
5505 	    if (ioReturnValue != kIOReturnSuccess || plugInInterface == NULL)
5506 	      {
5507 		DBG (5, "Error creating plugin interface (0x%08x)\n",
5508 		     ioReturnValue);
5509 		return;
5510 	      }
5511 
5512 	    scsiDeviceInterface = NULL;
5513 	    plugInResult = (*plugInInterface)->
5514 	      QueryInterface (plugInInterface,
5515 			      CFUUIDGetUUIDBytes (kIOSCSIDeviceInterfaceID),
5516 			      (LPVOID) & scsiDeviceInterface);
5517 	    if (plugInResult != S_OK || scsiDeviceInterface == NULL)
5518 	      {
5519 		DBG (5, "Couldn't create SCSI device interface (%ld)\n",
5520 		     plugInResult);
5521 		return;
5522 	      }
5523 
5524 	    (*plugInInterface)->Release (plugInInterface);
5525 	    IOObjectRelease (scsiDevice);
5526 
5527 	    ioReturnValue = (*scsiDeviceInterface)->
5528 	      getInquiryData (scsiDeviceInterface, &inquiry,
5529 			      sizeof (SCSIInquiry), &inquirySize);
5530 
5531 	    (*scsiDeviceInterface)->Release (scsiDeviceInterface);
5532 
5533 	    if ((findlun < 0 || findlun == scsilun) &&
5534 		(findvendor == NULL || strncmp (findvendor,
5535 						inquiry.vendorName,
5536 						strlen (findvendor)) == 0) &&
5537 		(findmodel == NULL || strncmp (findmodel,
5538 					       inquiry.productName,
5539 					       strlen (findmodel)) == 0))
5540 	      {
5541 		sprintf (devname, "u%dt%dl%d", iounit, scsitarget, scsilun);
5542 		(*attach) (devname);
5543 	      }
5544 	  }
5545 	IOObjectRelease (scsiObjectIterator);
5546       }
5547   }
5548 
5549 # endif	/* ifdef HAVE_IOKIT_CDB_IOSCSILIB_H */
5550 
5551 # if defined (HAVE_IOKIT_SCSI_SCSICOMMANDOPERATIONCODES_H) || \
5552      defined (HAVE_IOKIT_SCSI_COMMANDS_SCSICOMMANDOPERATIONCODES_H)
5553 
5554   static
CreateMatchingDictionaryForSTUC(SInt32 peripheralDeviceType,const char * findvendor,const char * findmodel,const CFDataRef scsiguid,CFMutableDictionaryRef * matchingDict)5555   void CreateMatchingDictionaryForSTUC (SInt32 peripheralDeviceType,
5556 					const char *findvendor,
5557 					const char *findmodel,
5558 					const CFDataRef scsiguid,
5559 					CFMutableDictionaryRef * matchingDict)
5560   {
5561     CFMutableDictionaryRef subDict;
5562     CFNumberRef deviceTypeRef;
5563     CFStringRef str;
5564 
5565     /* Create the dictionaries */
5566     *matchingDict =
5567       CFDictionaryCreateMutable (kCFAllocatorDefault, 0,
5568 				 &kCFTypeDictionaryKeyCallBacks,
5569 				 &kCFTypeDictionaryValueCallBacks);
5570     if (*matchingDict == NULL)
5571       {
5572 	return;
5573       }
5574 
5575     subDict =
5576       CFDictionaryCreateMutable (kCFAllocatorDefault, 0,
5577 				 &kCFTypeDictionaryKeyCallBacks,
5578 				 &kCFTypeDictionaryValueCallBacks);
5579     if (subDict == NULL)
5580       {
5581 	CFRelease (*matchingDict);
5582 	*matchingDict = NULL;
5583 	return;
5584       }
5585 
5586     /* Create a dictionary with the "SCSITaskDeviceCategory" key with the
5587        appropriate value for the device type we're interested in.*/
5588 
5589     CFDictionarySetValue (subDict,
5590 			  CFSTR (kIOPropertySCSITaskDeviceCategory),
5591 			  CFSTR (kIOPropertySCSITaskUserClientDevice));
5592 
5593     deviceTypeRef = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType,
5594 				    &peripheralDeviceType);
5595     CFDictionarySetValue (subDict,
5596 			  CFSTR (kIOPropertySCSIPeripheralDeviceType),
5597 			  deviceTypeRef);
5598     CFRelease (deviceTypeRef);
5599 
5600     /* Add search for a vendor or model */
5601 
5602     if (findvendor)
5603       {
5604 	str = CFStringCreateWithCString (kCFAllocatorDefault, findvendor,
5605 					 kCFStringEncodingUTF8);
5606 	CFDictionarySetValue (subDict,
5607 			      CFSTR (kIOPropertySCSIVendorIdentification),
5608 			      str);
5609 	CFRelease (str);
5610       }
5611     if (findmodel)
5612       {
5613 	str = CFStringCreateWithCString (kCFAllocatorDefault, findmodel,
5614 					 kCFStringEncodingUTF8);
5615 	CFDictionarySetValue (subDict,
5616 			      CFSTR (kIOPropertySCSIProductIdentification),
5617 			      str);
5618 	CFRelease (str);
5619       }
5620     if (scsiguid)
5621       {
5622 	CFDictionarySetValue (subDict,
5623 			      CFSTR
5624 			      (kIOPropertySCSITaskUserClientInstanceGUID),
5625 			      scsiguid);
5626       }
5627 
5628     /* Add the dictionary to the main dictionary with the key "IOPropertyMatch"
5629        to narrow the search to the above dictionary. */
5630 
5631     CFDictionarySetValue (*matchingDict, CFSTR (kIOPropertyMatchKey), subDict);
5632     CFRelease (subDict);
5633   }
5634 
5635   static
CreateDeviceInterfaceUsingSTUC(io_object_t scsiDevice,IOCFPlugInInterface *** thePlugInInterface,SCSITaskDeviceInterface *** theInterface)5636   void CreateDeviceInterfaceUsingSTUC (io_object_t scsiDevice,
5637 				       IOCFPlugInInterface ***
5638 				       thePlugInInterface,
5639 				       SCSITaskDeviceInterface ***
5640 				       theInterface)
5641   {
5642     IOReturn ioReturnValue;
5643     IOCFPlugInInterface **plugInInterface = NULL;
5644     SInt32 score = 0;
5645     HRESULT plugInResult;
5646     SCSITaskDeviceInterface **interface = NULL;
5647 
5648     /* Create the base interface of type IOCFPlugInInterface.
5649        This object will be used to create the SCSI device interface object. */
5650 
5651     ioReturnValue =
5652       IOCreatePlugInInterfaceForService (scsiDevice,
5653 					 kIOSCSITaskDeviceUserClientTypeID,
5654 					 kIOCFPlugInInterfaceID,
5655 					 &plugInInterface, &score);
5656     if (ioReturnValue != kIOReturnSuccess)
5657       {
5658 	DBG (5, "Error creating plugin interface (0x%08x)\n", ioReturnValue);
5659 	return;
5660       }
5661 
5662     /* Query the base plugin interface for an instance of the specific
5663        SCSI device interface object. */
5664 
5665     plugInResult =
5666       (*plugInInterface)->QueryInterface (plugInInterface,
5667 					  CFUUIDGetUUIDBytes
5668 					  (kIOSCSITaskDeviceInterfaceID),
5669 					  (LPVOID) & interface);
5670     if (plugInResult != S_OK)
5671       {
5672 	DBG (5, "Couldn't create SCSI device interface (%ld)\n",
5673 	     (long) plugInResult);
5674 	return;
5675       }
5676 
5677     /* Set the return values. */
5678 
5679     *thePlugInInterface = plugInInterface;
5680     *theInterface = interface;
5681   }
5682 
5683   static SANE_Status
ExecuteSCSITask(SCSITaskInterface ** task,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)5684     ExecuteSCSITask (SCSITaskInterface ** task,
5685 		     const void *cmd, size_t cmd_size,
5686 		     const void *src, size_t src_size,
5687 		     void *dst, size_t * dst_size)
5688   {
5689     SCSITaskStatus taskStatus;
5690     SCSI_Sense_Data senseData;
5691     SCSICommandDescriptorBlock cdb;
5692     IOReturn ioReturnValue;
5693 #ifdef HAVE_SCSITASKSGELEMENT
5694     SCSITaskSGElement range;
5695 #else
5696     IOVirtualRange range;
5697 #endif
5698     UInt64 transferCount = 0;
5699     UInt64 data_length = 0;
5700     UInt8 transferType = 0;
5701 
5702     if (dst && dst_size)	/* isRead */
5703       {
5704 	DBG (6, "isRead dst_size:%ld\n", *dst_size);
5705 
5706 	/* Zero the buffer. */
5707 	memset (dst, 0, *dst_size);
5708 
5709 	/* Configure the virtual range for the buffer. */
5710 	range.address = (long) dst;
5711 	range.length = *dst_size;
5712 
5713 	data_length = *dst_size;
5714 	transferType = kSCSIDataTransfer_FromTargetToInitiator;
5715       }
5716     else
5717       {
5718 	DBG (6, "isWrite src_size:%ld\n", src_size);
5719 
5720 	/* Configure the virtual range for the buffer. */
5721 	range.address = (long) src;
5722 	range.length = src_size;
5723 
5724 	data_length = src_size;
5725 	transferType = kSCSIDataTransfer_FromInitiatorToTarget;
5726       }
5727 
5728 
5729     /* zero the senseData and CDB */
5730     memset (&senseData, 0, sizeof (senseData));
5731     memset (cdb, 0, sizeof (cdb));
5732 
5733     /* copy the command data */
5734     memcpy (cdb, cmd, cmd_size);
5735 
5736     /* Set the actual cdb in the task */
5737     ioReturnValue = (*task)->SetCommandDescriptorBlock (task, cdb, cmd_size);
5738     if (ioReturnValue != kIOReturnSuccess)
5739       {
5740 	DBG (5, "Error setting CDB (0x%08x)\n", ioReturnValue);
5741 	return SANE_STATUS_IO_ERROR;
5742       }
5743 
5744     /* Set the scatter-gather entry in the task */
5745     ioReturnValue = (*task)->SetScatterGatherEntries (task, &range, 1,
5746 						      data_length,
5747 						      transferType);
5748     if (ioReturnValue != kIOReturnSuccess)
5749       {
5750 	DBG (5, "Error setting scatter-gather entries (0x%08x)\n",
5751 	     ioReturnValue);
5752 	return SANE_STATUS_IO_ERROR;
5753       }
5754 
5755     /* Set the timeout in the task */
5756     ioReturnValue = (*task)->SetTimeoutDuration (task,
5757 						 sane_scsicmd_timeout * 1000);
5758     if (ioReturnValue != kIOReturnSuccess)
5759       {
5760 	DBG (5, "Error setting timeout (0x%08x)\n", ioReturnValue);
5761 	return SANE_STATUS_IO_ERROR;
5762       }
5763 
5764     DBG (5, "Executing command\n");
5765 
5766     /* Send it! */
5767     ioReturnValue = (*task)->ExecuteTaskSync (task, &senseData, &taskStatus,
5768 					      &transferCount);
5769     if (ioReturnValue != kIOReturnSuccess)
5770       {
5771 	DBG (5, "Error executing task (0x%08x)\n", ioReturnValue);
5772 	return SANE_STATUS_IO_ERROR;
5773       }
5774 
5775     DBG (5, "ExecuteTaskSync OK Transferred %lld bytes\n", transferCount);
5776 
5777     if (taskStatus != kSCSITaskStatus_GOOD)
5778       {
5779 	DBG (5, "taskStatus = 0x%08x\n", taskStatus);
5780 	return SANE_STATUS_IO_ERROR;
5781       }
5782 
5783     /* Task worked correctly */
5784     if (dst && dst_size)
5785       *dst_size = transferCount;
5786 
5787     return SANE_STATUS_GOOD;
5788   }
5789 
5790   static SANE_Status
ExecuteCommandUsingSTUC(SCSITaskDeviceInterface ** interface,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)5791     ExecuteCommandUsingSTUC (SCSITaskDeviceInterface ** interface,
5792 			     const void *cmd, size_t cmd_size,
5793 			     const void *src, size_t src_size,
5794 			     void *dst, size_t * dst_size)
5795   {
5796     SCSITaskInterface **task;
5797     IOReturn ioReturnValue;
5798     SANE_Status returnValue;
5799 
5800     /* Get exclusive access for the device if we can. This must be done
5801        before any SCSITasks can be created and sent to the device. */
5802     ioReturnValue = (*interface)->ObtainExclusiveAccess (interface);
5803 
5804     if (ioReturnValue != kIOReturnSuccess)
5805       {
5806 	DBG (5, "ObtainExclusiveAccess failed (0x%08x)\n", ioReturnValue);
5807 	return SANE_STATUS_NO_MEM;
5808       }
5809 
5810     /* Create a task now that we have exclusive access */
5811     task = (*interface)->CreateSCSITask (interface);
5812 
5813     if (task == NULL)
5814       {
5815 	DBG (5, "CreateSCSITask returned NULL\n");
5816 	(*interface)->ReleaseExclusiveAccess (interface);
5817 	return SANE_STATUS_NO_MEM;
5818       }
5819 
5820     returnValue = ExecuteSCSITask (task, cmd, cmd_size,
5821 				   src, src_size, dst, dst_size);
5822 
5823     /* Release the task interface */
5824     (*task)->Release (task);
5825 
5826     /* Release exclusive access */
5827     (*interface)->ReleaseExclusiveAccess (interface);
5828 
5829     return returnValue;
5830   }
5831 
5832   static SANE_Status
sanei_scsi_cmd2_stuc_api(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)5833     sanei_scsi_cmd2_stuc_api (int fd,
5834 			      const void *cmd, size_t cmd_size,
5835 			      const void *src, size_t src_size,
5836 			      void *dst, size_t * dst_size)
5837   {
5838     CFDataRef guid;
5839     mach_port_t masterPort;
5840     int i;
5841     io_object_t scsiDevice;
5842     SInt32 peripheralDeviceType;
5843     CFMutableDictionaryRef matchingDict;
5844     io_iterator_t iokIterator;
5845     IOReturn ioReturnValue;
5846     IOCFPlugInInterface **plugInInterface = NULL;
5847     SCSITaskDeviceInterface **interface = NULL;
5848     io_object_t nextDevice;
5849     SANE_Status returnValue;
5850 
5851     guid = fd_info[fd].pdata;
5852     if (!guid)
5853       {
5854 	DBG (5, "No GUID\n");
5855 	return SANE_STATUS_INVAL;
5856       }
5857 
5858     DBG (2, "cmd2: cmd_size:%ld src_size:%ld dst_size:%ld isWrite:%d\n",
5859 	 cmd_size, src_size, (!dst_size) ? 0 : *dst_size, (!dst_size) ? 1 : 0);
5860 
5861     /* Use default master port */
5862     masterPort = 0;
5863     ioReturnValue = IOMasterPort (MACH_PORT_NULL, &masterPort);
5864     if (ioReturnValue != kIOReturnSuccess || masterPort == 0)
5865       {
5866 	DBG (5, "Could not get I/O master port (0x%08x)\n", ioReturnValue);
5867 	return SANE_STATUS_IO_ERROR;
5868       }
5869 
5870     /* Search for both Scanner type and Processor type devices */
5871     /* GB TDB This should only be needed for find */
5872     scsiDevice = 0;
5873     for (i = 0; !scsiDevice && i < 2; i++)
5874       {
5875 	peripheralDeviceType =
5876 	  (i == 0 ? kINQUIRY_PERIPHERAL_TYPE_ScannerSCSI2Device :
5877 	            kINQUIRY_PERIPHERAL_TYPE_ProcessorSPCDevice);
5878 
5879 	/* Set up a matching dictionary to search the I/O Registry for
5880 	   the SCSI device */
5881 	/* we are interested in, specifying the SCSITaskUserClient GUID. */
5882 	matchingDict = NULL;
5883 	CreateMatchingDictionaryForSTUC (peripheralDeviceType, NULL, NULL,
5884 					 guid, &matchingDict);
5885 	if (matchingDict == NULL)
5886 	  {
5887 	    DBG (5, "CreateMatchingDictionaryForSTUC Failed\n");
5888 	    return SANE_STATUS_NO_MEM;
5889 	  }
5890 
5891 	/* Now search I/O Registry for the matching device */
5892 	iokIterator = 0;
5893 	ioReturnValue =
5894 	  IOServiceGetMatchingServices (masterPort, matchingDict,
5895 					&iokIterator);
5896 	if (ioReturnValue != kIOReturnSuccess)
5897 	  {
5898 	    DBG (5, "IOServiceGetMatchingServices Failed\n");
5899 	    return SANE_STATUS_NO_MEM;
5900 	  }
5901 
5902 	scsiDevice = IOIteratorNext (iokIterator);
5903 
5904 	while ((nextDevice = IOIteratorNext (iokIterator)))
5905 	  {
5906 	    IOObjectRelease (nextDevice);
5907 	  }
5908 
5909 	IOObjectRelease (iokIterator);
5910       }
5911 
5912     if (!scsiDevice)
5913       {
5914 	DBG (5, "Device not found\n");
5915 	return SANE_STATUS_INVAL;
5916       }
5917 
5918     /* Found Device */
5919     /* Create interface */
5920 
5921     CreateDeviceInterfaceUsingSTUC (scsiDevice, &plugInInterface, &interface);
5922 
5923     /* Done with SCSI object from I/O Registry. */
5924     ioReturnValue = IOObjectRelease (scsiDevice);
5925 
5926     returnValue = SANE_STATUS_IO_ERROR;
5927 
5928     if (ioReturnValue != kIOReturnSuccess)
5929       {
5930 	DBG (5, "Error releasing SCSI device. (0x%08x)\n", ioReturnValue);
5931       }
5932     else if (interface != NULL)
5933       {
5934 	/* Execute the command */
5935 	returnValue =
5936 	  ExecuteCommandUsingSTUC (interface, cmd, cmd_size, src, src_size,
5937 				   dst, dst_size);
5938       }
5939 
5940     if (interface != NULL)
5941       {
5942 	(*interface)->Release (interface);
5943       }
5944 
5945     if (plugInInterface != NULL)
5946       {
5947 	IODestroyPlugInInterface (plugInInterface);
5948       }
5949 
5950     return returnValue;
5951   }
5952 
5953   static void
sanei_scsi_find_devices_stuc_api(const char * findvendor,const char * findmodel,const char * findtype,int findbus,int findchannel,int findid,int findlun,SANE_Status (* attach)(const char * dev))5954     sanei_scsi_find_devices_stuc_api (const char *findvendor,
5955 				      const char *findmodel,
5956 				      const char *findtype, int findbus,
5957 				      int findchannel, int findid, int findlun,
5958 				      SANE_Status (*attach) (const char *dev))
5959   {
5960     mach_port_t masterPort;
5961     IOReturn ioReturnValue;
5962     int i;
5963     SInt32 peripheralDeviceType;
5964     CFMutableDictionaryRef matchingDict;
5965     io_iterator_t iokIterator;
5966     io_object_t scsiDevice;
5967     CFDataRef GUIDRef;
5968     char *devname;
5969     int len;
5970     const unsigned char *p;
5971     CFDictionaryRef protocolCharacteristics;
5972     CFNumberRef scsiLunRef;
5973     int scsilun;
5974 
5975     masterPort = 0;
5976     ioReturnValue = IOMasterPort (MACH_PORT_NULL, &masterPort);
5977     if (ioReturnValue != kIOReturnSuccess || masterPort == 0)
5978       return;
5979 
5980     DBG (5, "Search for Vendor: %s Model: %s\n",
5981 	 (findvendor) ? findvendor : "(none)",
5982 	 (findmodel) ? findmodel : "(none)");
5983 
5984     /* Search for both Scanner type and Processor type devices */
5985 
5986     for (i = 0; i < 2; i++)
5987       {
5988 	peripheralDeviceType =
5989 	  (i == 0 ? kINQUIRY_PERIPHERAL_TYPE_ScannerSCSI2Device :
5990 	            kINQUIRY_PERIPHERAL_TYPE_ProcessorSPCDevice);
5991 
5992 	/* Set up a matching dictionary to search the I/O Registry for SCSI
5993 	   devices we are interested in. */
5994 
5995 	matchingDict = NULL;
5996 	CreateMatchingDictionaryForSTUC (peripheralDeviceType, findvendor,
5997 					 findmodel, NULL, &matchingDict);
5998 	if (matchingDict == NULL)
5999 	  {
6000 	    DBG (5, "CreateMatchingDictionaryForSTUC Failed\n");
6001 	    return;
6002 	  }
6003 
6004 	/* Now search I/O Registry for matching devices. */
6005 
6006 	iokIterator = 0;
6007 	ioReturnValue =
6008 	  IOServiceGetMatchingServices (masterPort, matchingDict,
6009 					&iokIterator);
6010 	if (ioReturnValue != kIOReturnSuccess)
6011 	  {
6012 	    DBG (5, "IOServiceGetMatchingServices Failed\n");
6013 	    return;
6014 	  }
6015 
6016 	/* Check devices */
6017 
6018 	while ((scsiDevice = IOIteratorNext (iokIterator)))
6019 	  {
6020 	    scsilun = 0;
6021             protocolCharacteristics = IORegistryEntryCreateCFProperty
6022 	      (scsiDevice, CFSTR ("Protocol Characteristics"), NULL, 0);
6023 	    if (protocolCharacteristics)
6024 	      {
6025 		scsiLunRef = CFDictionaryGetValue
6026 		  (protocolCharacteristics,
6027 		   CFSTR ("SCSI Logical Unit Number"));
6028 		if (scsiLunRef)
6029 		  CFNumberGetValue (scsiLunRef, kCFNumberIntType, &scsilun);
6030 		CFRelease (protocolCharacteristics);
6031 	      }
6032 
6033 	    if (findlun < 0 || findlun == scsilun)
6034 	      {
6035 		/* Create device name from the SCSITaskUserClient GUID */
6036 
6037 		GUIDRef = IORegistryEntryCreateCFProperty
6038 		  (scsiDevice,
6039 		   CFSTR (kIOPropertySCSITaskUserClientInstanceGUID),
6040 		   NULL, 0);
6041 
6042 		if (GUIDRef)
6043 		  {
6044 		    len = CFDataGetLength (GUIDRef);
6045 		    p = CFDataGetBytePtr (GUIDRef);
6046 
6047 		    devname = (char *) malloc (2 * len + 3);
6048 		    devname [0] = '<';
6049 		    for (i = 0; i < len; i++)
6050 		      sprintf (&devname [2 * i + 1], "%02x", p [i]);
6051 		    devname [2 * len + 1] = '>';
6052 		    devname [2 * len + 2] = '\0';
6053 
6054 		    CFRelease (GUIDRef);
6055 
6056 		    DBG (1, "Found: %s\n", devname);
6057 
6058 		    /* Attach to the device */
6059 		    (*attach) (devname);
6060 		    free (devname);
6061 		  }
6062 		else
6063 		  DBG (1, "Can't find SCSITaskUserClient GUID\n");
6064 	      }
6065 	  }
6066 	IOObjectRelease (iokIterator);
6067       }
6068   }
6069 
6070 # endif	/* HAVE_IOKIT_SCSI_COMMANDS_SCSICOMMANDOPERATIONCODES_H */
6071 
6072   SANE_Status
sanei_scsi_cmd2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size)6073     sanei_scsi_cmd2 (int fd,
6074 		     const void *cmd, size_t cmd_size,
6075 		     const void *src, size_t src_size,
6076 		     void *dst, size_t * dst_size)
6077   {
6078     if (fd_info[fd].pdata)
6079 # if defined (HAVE_IOKIT_SCSI_SCSICOMMANDOPERATIONCODES_H) || \
6080      defined (HAVE_IOKIT_SCSI_COMMANDS_SCSICOMMANDOPERATIONCODES_H)
6081       return sanei_scsi_cmd2_stuc_api (fd, cmd, cmd_size, src, src_size,
6082 				       dst, dst_size);
6083 # else
6084       return SANE_STATUS_INVAL;
6085 # endif
6086     else
6087 # ifdef HAVE_IOKIT_CDB_IOSCSILIB_H
6088       return sanei_scsi_cmd2_old_api (fd, cmd, cmd_size, src, src_size,
6089 				      dst, dst_size);
6090 # else
6091       return SANE_STATUS_INVAL;
6092 # endif
6093   }
6094 
6095   void
sanei_scsi_find_devices(const char * findvendor,const char * findmodel,const char * findtype,int findbus,int findchannel,int findid,int findlun,SANE_Status (* attach)(const char * dev))6096     sanei_scsi_find_devices (const char *findvendor, const char *findmodel,
6097 			     const char *findtype,
6098 			     int findbus, int findchannel, int findid,
6099 			     int findlun,
6100 			     SANE_Status (*attach) (const char *dev))
6101   {
6102 # if defined (HAVE_IOKIT_SCSI_SCSICOMMANDOPERATIONCODES_H) || \
6103      defined (HAVE_IOKIT_SCSI_COMMANDS_SCSICOMMANDOPERATIONCODES_H)
6104     sanei_scsi_find_devices_stuc_api (findvendor, findmodel, findtype,
6105 				      findbus, findchannel, findid,
6106 				      findlun, attach);
6107 # endif
6108 # ifdef HAVE_IOKIT_CDB_IOSCSILIB_H
6109     sanei_scsi_find_devices_old_api (findvendor, findmodel, findtype,
6110 				     findbus, findchannel, findid,
6111 				     findlun, attach);
6112 # endif
6113   }
6114 
6115 #define WE_HAVE_FIND_DEVICES
6116 
6117 #endif /* USE == MACOSX_INTERFACE */
6118 
6119 
6120 #ifndef WE_HAVE_ASYNC_SCSI
6121 
6122   SANE_Status
sanei_scsi_req_enter2(int fd,const void * cmd,size_t cmd_size,const void * src,size_t src_size,void * dst,size_t * dst_size,void ** idp)6123     sanei_scsi_req_enter2 (int fd, const void *cmd, size_t cmd_size,
6124 			   const void *src, size_t src_size,
6125 			   void *dst, size_t * dst_size, void **idp)
6126   {
6127     return sanei_scsi_cmd2 (fd, cmd, cmd_size, src, src_size, dst, dst_size);
6128   }
6129 
sanei_scsi_req_wait(void * id)6130   SANE_Status sanei_scsi_req_wait (void *id)
6131   {
6132     return SANE_STATUS_GOOD;
6133   }
6134 
sanei_scsi_req_flush_all(void)6135   void sanei_scsi_req_flush_all (void)
6136   {
6137   }
6138 
sanei_scsi_req_flush_all_extended(int fd)6139   void sanei_scsi_req_flush_all_extended (int fd)
6140   {
6141   }
6142 
6143 #endif /* WE_HAVE_ASYNC_SCSI */
6144 
sanei_scsi_req_enter(int fd,const void * src,size_t src_size,void * dst,size_t * dst_size,void ** idp)6145   SANE_Status sanei_scsi_req_enter (int fd,
6146 				    const void *src, size_t src_size,
6147 				    void *dst, size_t * dst_size, void **idp)
6148   {
6149     size_t cmd_size = CDB_SIZE (*(const char *) src);
6150 
6151     if (dst_size && *dst_size)
6152       assert (src_size == cmd_size);
6153     else
6154       assert (src_size >= cmd_size);
6155 
6156     return sanei_scsi_req_enter2 (fd, src, cmd_size,
6157 				  (const char *) src + cmd_size,
6158 				  src_size - cmd_size, dst, dst_size, idp);
6159   }
6160 
6161   SANE_Status
sanei_scsi_cmd(int fd,const void * src,size_t src_size,void * dst,size_t * dst_size)6162     sanei_scsi_cmd (int fd, const void *src, size_t src_size,
6163 		    void *dst, size_t * dst_size)
6164   {
6165     size_t cmd_size = CDB_SIZE (*(const char *) src);
6166 
6167     if (dst_size && *dst_size)
6168       assert (src_size == cmd_size);
6169     else
6170       assert (src_size >= cmd_size);
6171 
6172     return sanei_scsi_cmd2 (fd, src, cmd_size,
6173 			    (const char *) src + cmd_size,
6174 			    src_size - cmd_size, dst, dst_size);
6175   }
6176 
6177 
6178 
6179 #ifndef WE_HAVE_FIND_DEVICES
6180 
6181   void
sanei_scsi_find_devices(const char * findvendor,const char * findmodel,const char * findtype,int findbus,int findchannel,int findid,int findlun,SANE_Status (* attach)(const char * dev))6182     sanei_scsi_find_devices (const char *findvendor, const char *findmodel,
6183 			     const char *findtype,
6184 			     int findbus, int findchannel, int findid,
6185 			     int findlun,
6186 			     SANE_Status (*attach) (const char *dev))
6187   {
6188     DBG_INIT ();
6189     DBG (1, "sanei_scsi_find_devices: not implemented for this platform\n");
6190   }
6191 
6192 #endif /* WE_HAVE_FIND_DEVICES */
6193