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