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