xref: /third_party/backends/sanei/sanei_scsi.c (revision 141cc406)
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
242static int cam_fd = -1;		/* used for SCSI CAM based interfaces */
243#endif
244
245#if USE == SOLARIS_INTERFACE || USE == SOLARIS_USCSI_INTERFACE
246static 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 */
260static 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 */
315static int sane_scsicmd_timeout = 120;
316int 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*/
354typedef 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}
366SG_scsi_id;
367
368typedef 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}
407req;
408
409typedef 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}
415fdparms;
416
417#endif
418
419#if USE == FREEBSD_CAM_INTERFACE
420# define CAM_MAXDEVS	128
421struct cam_device *cam_devices[CAM_MAXDEVS] = { NULL };
422#endif
423
424static 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
435static 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
452int ServerInitialized = 0;
453pid_t ServerPID;
454struct DomainServerCommon *com;
455long CommandTriggerValue[2];
456ec2_$ptr_t CommandAcceptedPtr[2];
457long ResultTriggerValue[2];
458ec2_$ptr_t ResultReadyPtr[2];
459time_$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. */
467static void
468KillDomainServer (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:  */
517static HFILE driver_handle = 0;	/* file handle for device driver */
518static PVOID aspi_buf = 0;	/* Big data buffer locked by driver. */
519static int aspi_ref_count = 0;	/* # of fds using ASPI */
520static SRB *PSRBlock = 0;	/* SCSI Request Block */
521static 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.  */
536static int
537open_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
767static void
768close_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
796static int num_alloced = 0;
797
798#if USE == LINUX_INTERFACE
799
800static int sg_version = 0;
801
802static SANE_Status
803get_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
859SANE_Status
860sanei_scsi_open_extended (const char *dev, int *fdp,
861			  SANEI_SCSI_Sense_Handler handler,
862			  void *handler_arg, int *buffersize)
863#else
864
865SANE_Status
866sanei_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 */
1506SANE_Status
1507sanei_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 */
1549SANE_Status
1550sanei_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
1562void
1563sanei_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
1655void
1656sanei_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
1668SANE_Status
1669sanei_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
1804SANE_Status
1805sanei_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
1814SANE_Status
1815sanei_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
1845static int pack_id = 0;
1846static int need_init = 1;
1847static sigset_t all_signals;
1848
1849#define ATOMIC(s)					\
1850do							\
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  }							\
1863while (0)
1864
1865static void
1866issue (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
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
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
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
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
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) */
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 */
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
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
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 */
2696static void /* calls 'attach' function pointer with sg device file name iff match */
2697sanei_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 */
2915static 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
2937void /* calls 'attach' function pointer with sg device file name iff match */
2938sanei_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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
5014SANE_Status
5015sanei_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. */
5100void
5101sanei_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
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
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
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
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
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
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
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
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
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
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
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
6124  SANE_Status sanei_scsi_req_wait (void *id)
6125  {
6126    return SANE_STATUS_GOOD;
6127  }
6128
6129  void sanei_scsi_req_flush_all (void)
6130  {
6131  }
6132
6133  void sanei_scsi_req_flush_all_extended (int fd)
6134  {
6135  }
6136
6137#endif /* WE_HAVE_ASYNC_SCSI */
6138
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
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
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