Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / libusal / scsi-wnt.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /* @(#)scsi-wnt.c       1.45 04/07/19 Copyright 1998-2004 J. Schilling, A.L. Faber, J.A. Key */
14 /*
15  *      Interface for the Win32 ASPI library.
16  *              You need wnaspi32.dll and aspi32.sys
17  *              Both can be installed from ASPI_ME
18  *
19  *      Warning: you may change this source, but if you do that
20  *      you need to change the _usal_version and _usal_auth* string below.
21  *      You may not return "schily" for an SCG_AUTHOR request anymore.
22  *      Choose your name instead of "schily" and make clear that the version
23  *      string is related to a modified source.
24  *
25  *      Copyright (c) 1998-2004 J. Schilling
26  *      Copyright (c) 1999 A.L. Faber for the first implementation
27  *                         of this interface.
28  *      TODO:
29  *      -       DMA resid handling
30  *      -       better handling of maxDMA
31  *      -       SCSI reset support
32  */
33 /*
34  * This program is free software; you can redistribute it and/or modify
35  * it under the terms of the GNU General Public License version 2
36  * as published by the Free Software Foundation.
37  *
38  * This program is distributed in the hope that it will be useful,
39  * but WITHOUT ANY WARRANTY; without even the implied warranty of
40  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
41  * GNU General Public License for more details.
42  *
43  * You should have received a copy of the GNU General Public License along with
44  * this program; see the file COPYING.  If not, write to the Free Software
45  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
46  */
47
48
49 /*
50  * Include for Win32 ASPI AspiRouter
51  *
52  * NOTE: aspi-win32.h includes Windows.h and Windows.h includes
53  *       Base.h which has a second typedef for BOOL.
54  *       We define BOOL to make all local code use BOOL
55  *       from Windows.h and use the hidden __SBOOL for
56  *       our global interfaces.
57  */
58 #define BOOL    WBOOL           /* This is the Win BOOL         */
59 #define format  __format
60 #include <usal/aspi-win32.h>
61 #include <usal/spti-wnt.h>
62 #undef format
63
64 #ifdef  __CYGWIN32__            /* Use dlopen()                 */
65 #include <dlfcn.h>
66 #endif
67
68 /*
69  *      Warning: you may change this source, but if you do that
70  *      you need to change the _usal_version and _usal_auth* string below.
71  *      You may not return "schily" for an SCG_AUTHOR request anymore.
72  *      Choose your name instead of "schily" and make clear that the version
73  *      string is related to a modified source.
74  */
75 static  char    _usal_trans_version[] = "scsi-wnt.c-1.45";      /* The version for this transport*/
76 static  char    _usal_itrans_version[] = "SPTI-scsi-wnt.c-1.45";        /* The version for SPTI */
77
78 /*
79  * Local defines and constants
80  */
81 /*#define DEBUG_WNTASPI*/
82
83 #define MAX_SCG         16      /* Max # of SCSI controllers    */
84 #define MAX_TGT         16      /* Max # of SCSI Targets        */
85 #define MAX_LUN         8       /* Max # of SCSI LUNs           */
86
87 #ifdef DEBUG_WNTASPI
88 #endif
89
90 struct usal_local {
91         int     dummy;
92         char *filenames[MAX_SCG][MAX_TGT][MAX_LUN];
93         char drive_wanted;
94 };
95 #define usallocal(p)    ((struct usal_local *)((p)->local))
96
97 /*
98  * Local variables
99  */
100 static  int     busses;
101 static  DWORD   (*pfnGetASPI32SupportInfo)(void)                = NULL;
102 static  DWORD   (*pfnSendASPI32Command)(LPSRB)                  = NULL;
103 static  BOOL    (*pfnGetASPI32Buffer)(PASPI32BUFF)              = NULL;
104 static  BOOL    (*pfnFreeASPI32Buffer)(PASPI32BUFF)             = NULL;
105 static  BOOL    (*pfnTranslateASPI32Address)(PDWORD, PDWORD)    = NULL;
106
107 static  int     DriverLoaded                    = 0;    /* ASPI or SPTI */
108 static  HANDLE  hAspiLib                        = NULL; /* Used for Loadlib */
109
110 #define MAX_DMA_WNT     (63L*1024L) /* ASPI-Driver  allows up to 64k ??? */
111
112 /*
113  * Local function prototypes
114  */
115 static  void    exit_func(void);
116 #ifdef DEBUG_WNTASPI
117 static  void    DebugScsiSend(SCSI *usalp, SRB_ExecSCSICmd *s, int bDisplayBuffer);
118 #endif
119 static  void    copy_sensedata(SRB_ExecSCSICmd *cp, struct usal_cmd *sp);
120 static  void    set_error(SRB_ExecSCSICmd *cp, struct usal_cmd *sp);
121 static  BOOL    open_driver(SCSI *usalp);
122 static  BOOL    load_aspi(SCSI *usalp);
123 static  BOOL    close_driver(void);
124 static  int     ha_inquiry(SCSI *usalp, int id, SRB_HAInquiry   *ip);
125 #ifdef  __USED__
126 static  int     resetSCSIBus(SCSI *usalp);
127 #endif
128 static  int     scsiabort(SCSI *usalp, SRB_ExecSCSICmd *sp);
129
130
131 /* SPTI Start ---------------------------------------------------------------*/
132 /*
133  * From scsipt.c - Copyright (C) 1999 Jay A. Key
134  * Homepage: http://akrip.sourceforge.net/
135  * Native NT support functions via the SCSI Pass Through interface instead
136  * of ASPI.  Although based on information from the NT 4.0 DDK from
137  * Microsoft, the information has been sufficiently distilled to allow
138  * compilation w/o having the DDK installed.
139  * added to scsi-wnt.c by Richard Stemmer, rs@epost.de
140  * See http://www.ste-home.de/cdrtools-spti/
141  */
142
143 #define PREFER_SPTI     1               /* Prefer SPTI if available, else try ASPI, force ASPI with dev=ASPI: */
144 /* #define      CREATE_NONSHARED 1 */   /* open CDROM-Device not SHARED if possible */
145 /* #define      _DEBUG_SCSIPT 1   */
146 #ifdef _DEBUG_SCSIPT
147 FILE *usalp_errfile; /* File for SPTI-Debug-Messages */
148 #endif
149
150 #define SENSE_LEN_SPTI          32      /* Sense length for ASPI is only 14 */
151 #define NUM_MAX_NTSCSI_DRIVES   26      /* a: ... z:                    */
152 #define NUM_FLOPPY_DRIVES       2
153 #define NUM_MAX_NTSCSI_HA       NUM_MAX_NTSCSI_DRIVES
154
155 #define NTSCSI_HA_INQUIRY_SIZE  36
156
157 #define SCSI_CMD_INQUIRY        0x12
158
159 typedef struct {
160         BYTE    ha;                     /* SCSI Bus #                   */
161         BYTE    tgt;                    /* SCSI Target #                */
162         BYTE    lun;                    /* SCSI Lun #                   */
163         BYTE    PortNumber;             /* SCSI Card # (\\.\SCSI%d)     */
164         BYTE    PathId;                 /* SCSI Bus/Channel # on card n */
165         BYTE    driveLetter;            /* Win32 drive letter (e.g. c:) */
166         BOOL    bUsed;                  /* Win32 drive letter is used   */
167         HANDLE  hDevice;                /* Win32 handle for ioctl()     */
168         BYTE    inqData[NTSCSI_HA_INQUIRY_SIZE];
169 } DRIVE;
170
171 typedef struct {
172         BYTE    numAdapters;
173         DRIVE   drive[NUM_MAX_NTSCSI_DRIVES];
174 } SPTIGLOBAL;
175
176 static  int     InitSCSIPT(SCSI *usalp);
177 static  int     DeinitSCSIPT(void);
178 static  void    GetDriveInformation(BYTE i, DRIVE *pDrive);
179 static  BYTE    SPTIGetNumAdapters(void);
180 static  BYTE    SPTIGetDeviceIndex(BYTE ha, BYTE tgt, BYTE lun);
181 static  DWORD   SPTIHandleHaInquiry(LPSRB_HAInquiry lpsrb);
182 static  DWORD   SPTIExecSCSICommand(LPSRB_ExecSCSICmd lpsrb, int sptTimeOutValue, BOOL bBeenHereBefore);
183 static  HANDLE  GetFileHandle(BYTE i, BOOL openshared);
184
185 static  BOOL    bSCSIPTInit = FALSE;
186 static  SPTIGLOBAL sptiglobal;
187 static  BOOL    UsingSPTI = FALSE;
188 static  BOOL    ForceAccess = FALSE;
189 static  int     sptihamax;
190 static  USHORT  sptihasortarr[NUM_MAX_NTSCSI_HA];
191
192 /*
193  * Initialization of SCSI Pass Through Interface code.  Responsible for
194  * setting up the array of SCSI devices.  This code will be a little
195  * different from the normal code -- it will query each drive letter from
196  * C: through Z: to see if it is  a CD.  When we identify a CD, we then
197  * send CDB with the INQUIRY command to it -- NT will automagically fill in
198  * the PathId, TargetId, and Lun for us.
199  */
200 static int InitSCSIPT(SCSI *usalp) {
201         BYTE    i;
202         BYTE    j;
203         char    buf[4];
204         UINT    uDriveType;
205         int     retVal = 0;
206         USHORT hasortval;
207         char adapter_name[20];
208         HANDLE  fh;
209         ULONG   returned;
210         BOOL    status;
211         char    InquiryBuffer[2048];
212         PSCSI_ADAPTER_BUS_INFO  ai;
213         BYTE    bus;
214         int     id_wanted=-1;
215
216         if (bSCSIPTInit)
217                 return (0);
218
219         /*
220          * Detect all Busses on all SCSI-Adapters
221          * Fill up map array that allows us to later assign devices to
222          * bus numbers.
223          */
224         sptihamax = 0;
225         i = 0;
226         do {
227                 snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\SCSI%d:", i);
228                 fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE,
229                                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
230                                                 NULL,
231                                                 OPEN_EXISTING, 0, NULL);
232                 if (fh != INVALID_HANDLE_VALUE) {
233                         status  = DeviceIoControl(fh,
234                                                 IOCTL_SCSI_GET_INQUIRY_DATA,
235                                                 NULL,
236                                                 0,
237                                                 InquiryBuffer,
238                                                 2048,
239                                                 &returned,
240                                                 FALSE);
241                         if (status) {
242                                 ai = (PSCSI_ADAPTER_BUS_INFO) InquiryBuffer;
243                                 for (bus = 0; bus < ai->NumberOfBusses; bus++) {
244                                         sptihasortarr[sptihamax] = ((i<<8) | bus);
245                                         sptihamax++;
246                                 }
247                         }
248                         CloseHandle(fh);
249                 }
250                 i++;
251         } while (fh != INVALID_HANDLE_VALUE);
252
253         errno = 0;
254         memset(&sptiglobal, 0, sizeof (SPTIGLOBAL));
255         for (i = 0; i < NUM_MAX_NTSCSI_DRIVES; i++)
256                 sptiglobal.drive[i].hDevice = INVALID_HANDLE_VALUE;
257
258         for (i = NUM_FLOPPY_DRIVES; i < NUM_MAX_NTSCSI_DRIVES; i++) {
259                 snprintf(buf, sizeof (buf), "%c:\\", (char)('A'+i));
260                 uDriveType = GetDriveType(buf);
261 #ifdef  CDROM_ONLY
262                 if (uDriveType == DRIVE_CDROM) {
263 #else
264                 if (TRUE) {
265 #endif
266                         GetDriveInformation(i, &sptiglobal.drive[i]);
267
268                         if (sptiglobal.drive[i].bUsed) {
269                                 retVal++;
270                                 hasortval = (sptiglobal.drive[i].PortNumber<<8) | sptiglobal.drive[i].PathId;
271                                 for (j = 0; j < sptihamax; j++) {
272                                         if (hasortval <= sptihasortarr[j])
273                                                 break;
274                                 }
275                                 if (j == sptihamax) {
276                                         sptihasortarr[j] = hasortval;
277                                         sptihamax++;
278                                 } else if (hasortval < sptihasortarr[j]) {
279                                         memmove(&sptihasortarr[j+1], &sptihasortarr[j], (sptihamax-j) * sizeof (USHORT));
280                                         sptihasortarr[j] = hasortval;
281                                         sptihamax++;
282                                 }
283
284                                 /* shortcut for device names, remember the hit */
285                                 if(uDriveType==DRIVE_CDROM && usalp->local) {
286                                         /* printf("seen, %d at %d, %d, %d\n", sptiglobal.drive[i].driveLetter, sptiglobal.drive[i].ha, sptiglobal.drive[i].tgt, sptiglobal.drive[i].lun); */
287                                        if(usallocal(usalp)->drive_wanted && *buf==toupper(usallocal(usalp)->drive_wanted))
288                                                id_wanted=i;
289                                        /* don't keep the names, serial search in _natname is sufficient */
290                                 }
291                         }
292                 }
293         }
294                 /* looks like a workaround for diverging ASPI and SPTI hostadapter numbers,
295                    most likely an attempt to keep the world of fake numbers
296                    consistent;
297                    EB */
298         if (sptihamax > 0) {
299                 for (i = NUM_FLOPPY_DRIVES; i < NUM_MAX_NTSCSI_DRIVES; i++)
300                         if (sptiglobal.drive[i].bUsed)
301                                 for (j = 0; j < sptihamax; j++) {
302                                         if (sptihasortarr[j] == ((sptiglobal.drive[i].PortNumber<<8) | sptiglobal.drive[i].PathId)) {
303                                                 sptiglobal.drive[i].ha = j;
304                                                 break;
305                                         }
306                                 }
307         }
308         sptiglobal.numAdapters = SPTIGetNumAdapters();
309
310         bSCSIPTInit = TRUE;
311         if(id_wanted>0) {
312                 usal_scsibus(usalp)=sptiglobal.drive[id_wanted].ha;
313                 usal_target(usalp) =sptiglobal.drive[id_wanted].tgt;
314                 usal_lun(usalp)    =sptiglobal.drive[id_wanted].lun;
315
316                 //#if 1
317                 #ifdef _DEBUG_SCSIPT
318                 fprintf(stderr, "named SCSIPT drive type %d found as %c, choosing %d, %d, %d\n", 
319                                 uDriveType,
320                                 'A'+id_wanted, 
321                                 usal_scsibus(usalp), 
322                                 usal_target(usalp), 
323                                 usal_lun(usalp));
324                 #endif
325         }
326
327         if (retVal > 0)
328                 UsingSPTI = TRUE;
329
330         return (retVal);
331 }
332
333
334 static int
335 DeinitSCSIPT(void)
336 {
337         BYTE    i;
338
339         if (!bSCSIPTInit)
340                 return (0);
341
342         for (i = NUM_FLOPPY_DRIVES; i < NUM_MAX_NTSCSI_DRIVES; i++) {
343                 if (sptiglobal.drive[i].bUsed) {
344                         CloseHandle(sptiglobal.drive[i].hDevice);
345                 }
346         }
347
348         sptiglobal.numAdapters = SPTIGetNumAdapters();
349
350         memset(&sptiglobal, 0, sizeof (SPTIGLOBAL));
351         bSCSIPTInit = FALSE;
352         return (-1);
353 }
354
355
356 /*
357  * Returns the number of "adapters" present.
358  */
359 static BYTE
360 SPTIGetNumAdapters(void)
361 {
362         BYTE    buf[256];
363         WORD    i;
364         BYTE    numAdapters = 0;
365
366         memset(buf, 0, 256);
367
368         /*
369          * PortNumber 0 should exist, so pre-mark it.  This avoids problems
370          * when the primary IDE drives are on PortNumber 0, but can't be opened
371          * because of insufficient privelege (ie. non-admin).
372          */
373         buf[0] = 1;
374         for (i = 0; i < NUM_MAX_NTSCSI_DRIVES; i++) {
375                 if (sptiglobal.drive[i].bUsed)
376                         buf[sptiglobal.drive[i].ha] = 1;
377         }
378
379         for (i = 0; i <= 255; i++)
380                 if (buf[i])
381                         numAdapters = (BYTE)(i + 1);
382
383 /*      numAdapters++; */
384
385         return (numAdapters);
386 }
387
388 #include <ctype.h>
389 static BOOL
390 w2k_or_newer(void)
391 {
392         OSVERSIONINFO osver;
393
394         memset(&osver, 0, sizeof (osver));
395         osver.dwOSVersionInfoSize = sizeof (osver);
396         GetVersionEx(&osver);
397         if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
398                 /*
399                  * Win2000 is NT-5.0, Win-XP is NT-5.1
400                  */
401                 if (osver.dwMajorVersion > 4)
402                         return (TRUE);
403         }
404         return (FALSE);
405 }
406
407 static BOOL
408 w2kstyle_create(void)
409 {
410         OSVERSIONINFO osver;
411
412 /*      return FALSE; */
413         memset(&osver, 0, sizeof (osver));
414         osver.dwOSVersionInfoSize = sizeof (osver);
415         GetVersionEx(&osver);
416         if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
417                 /*
418                  * Win2000 is NT-5.0, Win-XP is NT-5.1
419                  */
420                 if (osver.dwMajorVersion > 4)
421                         return (TRUE);
422
423                 if (osver.dwMajorVersion == 4) {                /* NT-4.x */
424                         char    *vers = osver.szCSDVersion;
425
426                         if (strlen(vers) == 0)
427                                 return (FALSE);
428
429                         /*
430                          * Servicepack is installed, skip over non-digit part
431                          */
432                         while (*vers != '\0' && !isdigit(*vers))
433                                 vers++;
434                         if (*vers == '\0')
435                                 return (FALSE);
436
437                         if (isdigit(vers[0]) &&
438                             (atoi(vers) >= 4 || isdigit(vers[1])))      /* Fom Service Pack 4 */
439                                 return (TRUE);                          /* same as for W2K */
440                 }
441         }
442         return (FALSE);
443 }
444
445
446 /*
447  * Universal function to get a file handle to the CD device.  Since
448  * NT 4.0 wants just the GENERIC_READ flag, and Win2K wants both
449  * GENERIC_READ and GENERIC_WRITE (why a read-only CD device needs
450  * GENERIC_WRITE access is beyond me...), the easist workaround is to just
451  * try them both.
452  */
453 static HANDLE
454 GetFileHandle(BYTE i, BOOL openshared)
455 {
456         char    buf[12];
457         HANDLE  fh;
458         DWORD   dwFlags = GENERIC_READ;
459         DWORD   dwAccessMode = 0;
460
461         dwAccessMode = FILE_SHARE_READ;
462         if (w2kstyle_create()) { /* if Win2K or greater, add GENERIC_WRITE */
463                 dwFlags |= GENERIC_WRITE;
464                 dwAccessMode |= FILE_SHARE_WRITE;
465 #ifdef _DEBUG_SCSIPT
466                 fprintf(usalp_errfile, "SPTI: GetFileHandle(): Setting for Win2K\n");
467 #endif
468         }
469         snprintf(buf, sizeof (buf), "\\\\.\\%c:", (char)('A'+i));
470 #ifdef CREATE_NONSHARED
471         if (openshared) {
472                 fh = CreateFile(buf, dwFlags, dwAccessMode, NULL,
473                                                 OPEN_EXISTING, 0, NULL);
474         } else {
475                 fh = CreateFile(buf, dwFlags, 0, NULL,
476                                                 OPEN_EXISTING, 0, NULL);
477         }
478         if (!openshared && fh == INVALID_HANDLE_VALUE && GetLastError() == ERROR_SHARING_VIOLATION)
479 #endif
480                 fh = CreateFile(buf, dwFlags, dwAccessMode, NULL,
481                                                 OPEN_EXISTING, 0, NULL);
482         if (fh == INVALID_HANDLE_VALUE) {
483                 /*
484                  * it went foobar somewhere, so try it with the GENERIC_WRITE
485                  * bit flipped
486                  */
487                 dwFlags ^= GENERIC_WRITE;
488                 dwAccessMode ^= FILE_SHARE_WRITE;
489 #ifdef CREATE_NONSHARED
490                 if (openshared) {
491                         fh = CreateFile(buf, dwFlags, dwAccessMode, NULL,
492                                                 OPEN_EXISTING, 0, NULL);
493                 } else {
494                         fh = CreateFile(buf, dwFlags, 0, NULL,
495                                                 OPEN_EXISTING, 0, NULL);
496                 }
497                 if (!openshared && fh == INVALID_HANDLE_VALUE && GetLastError() == ERROR_SHARING_VIOLATION)
498 #endif
499                         fh = CreateFile(buf, dwFlags, dwAccessMode, NULL,
500                                                 OPEN_EXISTING, 0, NULL);
501         }
502 #ifdef _DEBUG_SCSIPT
503         if (fh == INVALID_HANDLE_VALUE)
504                 fprintf(usalp_errfile, "SPTI: CreateFile() failed! -> %d\n", GetLastError());
505         else
506                 fprintf(usalp_errfile, "SPTI: CreateFile() returned %d\n", GetLastError());
507 #endif
508
509         return (fh);
510 }
511
512
513 /*
514  * fills in a pDrive structure with information from a SCSI_INQUIRY
515  * and obtains the ha:tgt:lun values via IOCTL_SCSI_GET_ADDRESS
516  */
517 static void GetDriveInformation(BYTE i, DRIVE *pDrive)
518 {
519         HANDLE          fh;
520         BOOL            status;
521         SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
522         SCSI_ADDRESS    scsiAddr;
523         ULONG           length;
524         ULONG           returned;
525         BYTE            inqData[NTSCSI_HA_INQUIRY_SIZE];
526
527 #ifdef _DEBUG_SCSIPT
528         fprintf(usalp_errfile, "SPTI: Checking drive %c:", 'A'+i);
529 #endif
530
531         fh = GetFileHandle(i, TRUE);    /* No NONSHARED Create for inquiry */
532
533         if (fh == INVALID_HANDLE_VALUE) {
534 #ifdef _DEBUG_SCSIPT
535                 fprintf(usalp_errfile, "       : fh == INVALID_HANDLE_VALUE\n");
536 #endif
537                 return;
538         }
539
540 #ifdef _DEBUG_SCSIPT
541         fprintf(usalp_errfile, "       : Index %d: fh == %08X\n", i, fh);
542 #endif
543
544
545         /*
546          * Get the drive inquiry data
547          */
548         memset(&swb, 0, sizeof (swb));
549         memset(inqData, 0, sizeof (inqData));
550         swb.spt.Length          = sizeof (SCSI_PASS_THROUGH_DIRECT);
551         swb.spt.CdbLength       = 6;
552         swb.spt.SenseInfoLength = 24;
553         swb.spt.DataIn          = SCSI_IOCTL_DATA_IN;
554         swb.spt.DataTransferLength = 100;
555         swb.spt.TimeOutValue    = 2;
556         swb.spt.DataBuffer      = inqData;
557         swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
558         swb.spt.Cdb[0]          = SCSI_CMD_INQUIRY;
559         swb.spt.Cdb[4]          = NTSCSI_HA_INQUIRY_SIZE;
560
561         length = sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
562         status = DeviceIoControl(fh,
563                             IOCTL_SCSI_PASS_THROUGH_DIRECT,
564                             &swb,
565                             sizeof (swb),
566                             &swb,
567                             sizeof (swb),
568                             &returned,
569                             NULL);
570
571         if (!status) {
572                 CloseHandle(fh);
573 #ifdef _DEBUG_SCSIPT
574                 fprintf(usalp_errfile, "SPTI: Error DeviceIoControl() -> %d\n", GetLastError());
575 #endif
576                 return;
577         }
578
579         memcpy(pDrive->inqData, inqData, NTSCSI_HA_INQUIRY_SIZE);
580
581         /*
582          * get the address (path/tgt/lun) of the drive via IOCTL_SCSI_GET_ADDRESS
583          */
584         memset(&scsiAddr, 0, sizeof (SCSI_ADDRESS));
585         scsiAddr.Length = sizeof (SCSI_ADDRESS);
586         if (DeviceIoControl(fh, IOCTL_SCSI_GET_ADDRESS, NULL, 0,
587                         &scsiAddr, sizeof (SCSI_ADDRESS), &returned,
588                         NULL)) {
589 #ifdef _DEBUG_SCSIPT
590                 fprintf(usalp_errfile, "Device %c: Port=%d, PathId=%d, TargetId=%d, Lun=%d\n",
591                         (char)i+'A', scsiAddr.PortNumber, scsiAddr.PathId,
592                         scsiAddr.TargetId, scsiAddr.Lun);
593 #endif
594                 pDrive->bUsed           = TRUE;
595                 pDrive->ha              = scsiAddr.PortNumber; /* preliminary */
596                 pDrive->PortNumber      = scsiAddr.PortNumber;
597                 pDrive->PathId          = scsiAddr.PathId;
598                 pDrive->tgt             = scsiAddr.TargetId;
599                 pDrive->lun             = scsiAddr.Lun;
600                 pDrive->driveLetter     = i;
601                 pDrive->hDevice         = INVALID_HANDLE_VALUE;
602
603         } else if (GetLastError() == 50) { /* support USB/FIREWIRE devices where this call is not supported assign drive letter as device ID */
604                 pDrive->bUsed = TRUE;
605                 pDrive->ha = i;
606                 pDrive->PortNumber = i+64; /* hopefully no conflict with other PortNumber */
607                 pDrive->PathId  = 0;
608                 pDrive->tgt = 0;
609                 pDrive->lun = 0;
610                 pDrive->driveLetter = i;
611                 pDrive->hDevice = INVALID_HANDLE_VALUE;
612 #ifdef _DEBUG_SCSIPT
613                 fprintf(usalp_errfile, "USB/Firewire Device %c: Port=%d, TargetId=%d, Lun=%d\n", (char)i+'A', i, 0, 0);
614 #endif
615         } else {
616                 pDrive->bUsed   = FALSE;
617 #ifdef _DEBUG_SCSIPT
618                 fprintf(usalp_errfile, "SPTI: Device %s: Error DeviceIoControl(): %d\n", (char)i+'A', GetLastError());
619 #endif
620                 CloseHandle(fh);
621                 return;
622         }
623 #ifdef _DEBUG_SCSIPT
624         fprintf(usalp_errfile,  "SPTI: Adding drive %c: (%d:%d:%d)\n", 'A'+i,
625                                         pDrive->ha, pDrive->tgt, pDrive->lun);
626 #endif
627         CloseHandle(fh);
628 }
629
630
631
632 static DWORD
633 SPTIHandleHaInquiry(LPSRB_HAInquiry lpsrb)
634 {
635         DWORD   *pMTL;
636
637         lpsrb->HA_Count    = sptiglobal.numAdapters;
638         if (lpsrb->SRB_HaId >= sptiglobal.numAdapters) {
639                 lpsrb->SRB_Status = SS_INVALID_HA;
640                 return (SS_INVALID_HA);
641         }
642         lpsrb->HA_SCSI_ID  = 7;                 /* who cares... we're not really an ASPI manager */
643         memcpy(lpsrb->HA_ManagerId,  "AKASPI v0.000001", 16);
644         memcpy(lpsrb->HA_Identifier, "SCSI Adapter    ", 16);
645         lpsrb->HA_Identifier[13] = (char)('0'+lpsrb->SRB_HaId);
646         memset(lpsrb->HA_Unique, 0, 16);
647         lpsrb->HA_Unique[3] = 8;
648         pMTL = (LPDWORD)&lpsrb->HA_Unique[4];
649         *pMTL = 64 * 1024;
650
651         lpsrb->SRB_Status = SS_COMP;
652         return (SS_COMP);
653 }
654
655 /*
656  * Looks up the index in the drive array for a given ha:tgt:lun triple
657  */
658 static BYTE
659 SPTIGetDeviceIndex(BYTE ha, BYTE tgt, BYTE lun)
660 {
661         BYTE    i;
662
663 #ifdef _DEBUG_SCSIPT
664         fprintf(usalp_errfile,  "SPTI: SPTIGetDeviceIndex, %d, %d, %d\n", ha,
665                         tgt, lun);
666 #endif
667
668         for (i = NUM_FLOPPY_DRIVES; i < NUM_MAX_NTSCSI_DRIVES; i++) {
669                 if (sptiglobal.drive[i].bUsed) {
670                         DRIVE   *lpd;
671
672                         lpd = &sptiglobal.drive[i];
673                         if ((lpd->ha == ha) && (lpd->tgt == tgt) && (lpd->lun == lun))
674                                 return (i);
675                 }
676         }
677
678         return (0);
679 }
680
681 /*
682  * Converts ASPI-style SRB to SCSI Pass Through IOCTL
683  */
684
685 static DWORD
686 SPTIExecSCSICommand(LPSRB_ExecSCSICmd lpsrb, int sptTimeOutValue, BOOL bBeenHereBefore)
687 {
688         BOOL    status;
689         SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
690         ULONG   length;
691         ULONG   returned;
692         BYTE    idx;
693         BYTE    j;
694
695         idx = SPTIGetDeviceIndex(lpsrb->SRB_HaId, lpsrb->SRB_Target, lpsrb->SRB_Lun);
696
697         if (idx == 0) {
698                 lpsrb->SRB_Status = SS_NO_DEVICE;
699                 return (SS_NO_DEVICE);
700         }
701
702         if (lpsrb->CDBByte[0] == SCSI_CMD_INQUIRY) {
703                 lpsrb->SRB_Status = SS_COMP;
704                 memcpy(lpsrb->SRB_BufPointer, sptiglobal.drive[idx].inqData, NTSCSI_HA_INQUIRY_SIZE);
705                 return (SS_COMP);
706         }
707
708         if (sptiglobal.drive[idx].hDevice == INVALID_HANDLE_VALUE)
709                 sptiglobal.drive[idx].hDevice = GetFileHandle(sptiglobal.drive[idx].driveLetter, FALSE);
710
711         memset(&swb, 0, sizeof (swb));
712         swb.spt.Length          = sizeof (SCSI_PASS_THROUGH);
713         swb.spt.CdbLength       = lpsrb->SRB_CDBLen;
714         if (lpsrb->SRB_Flags & SRB_DIR_IN)
715                 swb.spt.DataIn  = SCSI_IOCTL_DATA_IN;
716         else if (lpsrb->SRB_Flags & SRB_DIR_OUT)
717                 swb.spt.DataIn  = SCSI_IOCTL_DATA_OUT;
718         else
719                 swb.spt.DataIn  = SCSI_IOCTL_DATA_UNSPECIFIED;
720         swb.spt.DataTransferLength = lpsrb->SRB_BufLen;
721         swb.spt.TimeOutValue    = sptTimeOutValue;
722         swb.spt.SenseInfoLength = lpsrb->SRB_SenseLen;
723         swb.spt.DataBuffer      = lpsrb->SRB_BufPointer;
724         swb.spt.SenseInfoOffset =  offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
725         memcpy(swb.spt.Cdb, lpsrb->CDBByte, lpsrb->SRB_CDBLen);
726         length = sizeof (swb);
727
728 #ifdef _DEBUG_SCSIPT
729         fprintf(usalp_errfile, "SPTI: SPTIExecSCSICmd: calling DeviceIoControl()");
730         fprintf(usalp_errfile, "       : cmd == 0x%02X", swb.spt.Cdb[0]);
731 #endif
732         status = DeviceIoControl(sptiglobal.drive[idx].hDevice,
733                             IOCTL_SCSI_PASS_THROUGH_DIRECT,
734                             &swb,
735                             length,
736                             &swb,
737                             length,
738                             &returned,
739                             NULL);
740
741         lpsrb->SRB_SenseLen = swb.spt.SenseInfoLength;
742         memcpy(lpsrb->SenseArea, swb.ucSenseBuf, lpsrb->SRB_SenseLen);
743         if (status && swb.spt.ScsiStatus == 0) {
744                 lpsrb->SRB_Status = SS_COMP;
745 #ifdef _DEBUG_SCSIPT
746                 fprintf(usalp_errfile, "       : SRB_Status == SS_COMP\n");
747 #endif
748         } else {
749                 DWORD   dwErrCode;
750
751                 lpsrb->SRB_Status = SS_ERR;
752 /*              lpsrb->SRB_TargStat =  0x0004;*/
753                 lpsrb->SRB_TargStat =  swb.spt.ScsiStatus;
754
755                 dwErrCode = GetLastError();
756 #ifdef _DEBUG_SCSIPT
757                 fprintf(usalp_errfile, "       : error == %d   handle == %08X\n", dwErrCode, sptiglobal.drive[idx].hDevice);
758 #endif
759                 /*
760                  * KLUDGE ALERT! KLUDGE ALERT! KLUDGE ALERT!
761                  * Whenever a disk changer switches disks, it may render the device
762                  * handle invalid.  We try to catch these errors here and recover
763                  * from them.
764                  */
765                 if (!bBeenHereBefore &&
766                         ((dwErrCode == ERROR_MEDIA_CHANGED) || (dwErrCode == ERROR_INVALID_HANDLE))) {
767                         if (dwErrCode != ERROR_INVALID_HANDLE)
768                                 CloseHandle(sptiglobal.drive[idx].hDevice);
769                         GetDriveInformation(idx, &sptiglobal.drive[idx]);
770                         if (sptihamax > 0) {
771                                 if (sptiglobal.drive[idx].bUsed)
772                                         for (j = 0; j < sptihamax; j++) {
773                                                 if (sptihasortarr[j] ==
774                                                     ((sptiglobal.drive[idx].PortNumber << 8) | sptiglobal.drive[idx].PathId)) {
775                                                         sptiglobal.drive[idx].ha = j;
776                                                         break;
777                                                 }
778                                 }
779                         }
780 #ifdef _DEBUG_SCSIPT
781                         fprintf(usalp_errfile, "SPTI: SPTIExecSCSICommand: Retrying after ERROR_MEDIA_CHANGED\n");
782 #endif
783                         return (SPTIExecSCSICommand(lpsrb, sptTimeOutValue, TRUE));
784                 }
785         }
786         return (lpsrb->SRB_Status);
787 }
788 /* SPTI End -----------------------------------------------------------------*/
789
790
791 static void
792 exit_func()
793 {
794         if (!close_driver())
795                 errmsgno(EX_BAD, "Cannot close Win32-ASPI-Driver.\n");
796 }
797
798 /*
799  * Return version information for the low level SCSI transport code.
800  * This has been introduced to make it easier to trace down problems
801  * in applications.
802  */
803 static char *
804 usalo_version(SCSI *usalp, int what)
805 {
806         if (usalp != (SCSI *)0) {
807                 switch (what) {
808
809                 case SCG_VERSION:
810                         if (UsingSPTI)
811                                 return (_usal_itrans_version);
812                         return (_usal_trans_version);
813                 /*
814                  * If you changed this source, you are not allowed to
815                  * return "schily" for the SCG_AUTHOR request.
816                  */
817                 case SCG_AUTHOR:
818                         return (_usal_auth_cdrkit);
819                 case SCG_SCCS_ID:
820                         return (__sccsid);
821                 }
822         }
823         return ((char *)0);
824 }
825
826 static int
827 usalo_help(SCSI *usalp, FILE *f)
828 {
829         __usal_help(f, "ASPI", "Generic transport independent SCSI",
830                 "ASPI:", "bus,target,lun", "ASPI:1,2,0", TRUE, FALSE);
831         __usal_help(f, "SPTI", "Generic SCSI for Windows NT/2000/XP",
832                 "SPTI:", "bus,target,lun", "SPTI:1,2,0", TRUE, FALSE);
833         return (0);
834 }
835
836 static int
837 usalo_open(SCSI *usalp, char *device)
838 {
839         int     busno   = usal_scsibus(usalp);
840         int     tgt     = usal_target(usalp);
841         int     tlun    = usal_lun(usalp);
842
843         /*usal_local(usalp)->drive_wanted = NULL;
844         for(i=0;i<MAX_SCG*MAX_TGT*MAX_LUN;i++)
845                 usallocal(usalp)->filenames[i]=NULL;
846                 */
847         usalp->local = calloc(1, sizeof (struct usal_local));
848         if (usalp->local == NULL)
849                 return (0);
850
851         if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
852                 errno = EINVAL;
853                 if (usalp->errstr)
854                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
855                                 "Illegal value for busno, target or lun '%d,%d,%d'",
856                                 busno, tgt, tlun);
857                 return (-1);
858         }
859
860         /* Explicite choice of Schilling syntax */
861         if (device != NULL && (strcmp(device, "SPTI") == 0 || strcmp(device, "ASPI") == 0))
862                 goto devok;
863
864         /* use device as drive letter */
865         if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) {
866 /*
867                 errno = EINVAL;
868                 if (usalp->errstr)
869                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
870                                 "Open by 'devname' not supported on this OS");
871                 return (-1);
872 */
873
874                 UsingSPTI = TRUE;
875                 usallocal(usalp)->drive_wanted = *device;
876
877                 /* not the finest solution but prevents breaking on various
878                  * places for no good reasons... */
879                 usal_scsibus(usalp)=0;
880                 usal_target(usalp)=0;
881                 usal_lun(usalp)=0;
882                 goto openbydev;
883         }
884 devok:
885         if (DriverLoaded <= 0) {        /* do not change access method on open driver */
886                 ForceAccess = FALSE;
887 #ifdef PREFER_SPTI
888                 UsingSPTI = TRUE;
889 #else
890                 UsingSPTI = FALSE;
891 #endif
892                 if (!w2k_or_newer())
893                         UsingSPTI = FALSE;
894
895                 if (usalp->debug > 0) {
896                         fprintf((FILE *)usalp->errfile,
897                                 "usalo_open: Prefered SCSI transport: %s\n",
898                                         UsingSPTI ? "SPTI":"ASPI");
899                 }
900                 if (device != NULL && strcmp(device, "SPTI") == 0) {
901                         UsingSPTI = TRUE;
902                         ForceAccess = TRUE;
903                 } else if (device != NULL && strcmp(device, "ASPI") == 0) {
904                         UsingSPTI = FALSE;
905                         ForceAccess = TRUE;
906                 }
907                 if (device != NULL && usalp->debug > 0) {
908                         fprintf((FILE *)usalp->errfile,
909                                 "usalo_open: Selected SCSI transport: %s\n",
910                                         UsingSPTI ? "SPTI":"ASPI");
911                 }
912         }
913
914         /*
915          *  Check if variables are within the range
916          */
917         if (tgt >= 0 && tgt >= 0 && tlun >= 0) {
918                 /*
919                  * This is the non -scanbus case.
920                  */
921                 ;
922         } else if (tgt == -2 && tgt == -2 &&
923                     (tgt == -2 || tlun >= 0)) {
924                 /*
925                  * This is the dev=ASPI case.
926                  */
927                 ;
928         } else if (tgt != -1 || tgt != -1 || tlun != -1) {
929                 errno = EINVAL;
930                 return (-1);
931         }
932
933 openbydev:
934         /*
935          * Try to open ASPI-Router
936          */
937         if (!open_driver(usalp))
938                 return (-1);
939
940         /*
941          * More than we have ...
942          */
943         if (busno >= busses) {
944                 close_driver();
945                 return (-1);
946         }
947
948         /*
949          * Install Exit Function which closes the ASPI-Router
950          */
951         atexit(exit_func);
952
953         /*
954          * Success after all
955          */
956         return (1);
957 }
958
959 static int
960 usalo_close(SCSI *usalp)
961 {
962         int i;
963         /*
964         for(i=0;i<MAX_SCG*MAX_TGT*MAX_LUN;i++) {
965                 if(usallocal(usalp)->filenames[i]) {
966                         free(usallocal(usalp)->filenames[i]);
967                         usallocal(usalp)->filenames[i]=NULL;
968                 }
969         }
970         */
971         if(usalp->local) {
972                free(usalp->local);
973                usalp->local=NULL;
974         }
975         //printf("closing\n");
976
977         exit_func();
978         return (0);
979 }
980
981 static long
982 usalo_maxdma(SCSI *usalp, long amt)
983 {
984         return (MAX_DMA_WNT);
985 }
986
987 static void *
988 usalo_getbuf(SCSI *usalp, long amt)
989 {
990         if (usalp->debug > 0) {
991                 fprintf((FILE *)usalp->errfile,
992                                 "usalo_getbuf: %ld bytes\n", amt);
993         }
994         usalp->bufbase = malloc((size_t)(amt));
995         return (usalp->bufbase);
996 }
997
998 static void
999 usalo_freebuf(SCSI *usalp)
1000 {
1001         if (usalp->bufbase)
1002                 free(usalp->bufbase);
1003         usalp->bufbase = NULL;
1004 }
1005
1006 static __SBOOL
1007 usalo_havebus(SCSI *usalp, int busno)
1008 {
1009         if (busno < 0 || busno >= busses)
1010                 return (FALSE);
1011
1012         return (TRUE);
1013 }
1014
1015 static int
1016 usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun)
1017 {
1018         if (busno < 0 || busno >= busses ||
1019             tgt < 0 || tgt >= MAX_TGT ||
1020             tlun < 0 || tlun >= MAX_LUN)
1021                 return (-1);
1022
1023         /*
1024          * Return fake
1025          */
1026         return (1);
1027 }
1028
1029
1030 static int
1031 usalo_initiator_id(SCSI *usalp)
1032 {
1033         SRB_HAInquiry   s;
1034
1035         if (ha_inquiry(usalp, usal_scsibus(usalp), &s) < 0)
1036                 return (-1);
1037         return (s.HA_SCSI_ID);
1038 }
1039
1040 static int
1041 usalo_isatapi(SCSI *usalp)
1042 {
1043         return (-1);    /* XXX Need to add real test */
1044 }
1045
1046
1047 /*
1048  * XXX usalo_reset not yet tested
1049  */
1050 static int
1051 usalo_reset(SCSI *usalp, int what)
1052 {
1053
1054         DWORD                   Status = 0;
1055         DWORD                   EventStatus = WAIT_OBJECT_0;
1056         HANDLE                  Event    = NULL;
1057         SRB_BusDeviceReset      s;
1058
1059         if (what == SCG_RESET_NOP) {
1060                 if (UsingSPTI)
1061                         return (-1);
1062                 else
1063                         return (0);  /* Can ASPI really reset? */
1064         }
1065         if (what != SCG_RESET_BUS) {
1066                 errno = EINVAL;
1067                 return (-1);
1068         }
1069         if (UsingSPTI) {
1070                 fprintf((FILE *)usalp->errfile,
1071                                         "Reset SCSI device not implemented with SPTI\n");
1072                 return (-1);
1073         }
1074
1075         /*
1076          * XXX Does this reset TGT or BUS ???
1077          */
1078         if (usalp->debug > 0) {
1079                 fprintf((FILE *)usalp->errfile,
1080                                 "Attempting to reset SCSI device\n");
1081         }
1082
1083         /*
1084          * Check if ASPI library is loaded
1085          */
1086         if (DriverLoaded <= 0) {
1087                 fprintf((FILE *)usalp->errfile,
1088                                 "error in usalo_reset: ASPI driver not loaded !\n");
1089                 return (-1);
1090         }
1091
1092         memset(&s, 0, sizeof (s));      /* Clear SRB_BesDeviceReset structure */
1093
1094         Event = CreateEvent(NULL, TRUE, FALSE, NULL);
1095
1096         /*
1097          * Set structure variables
1098          */
1099         s.SRB_Cmd       = SC_RESET_DEV;                 /* ASPI command code = SC_RESET_DEV     */
1100         s.SRB_HaId      = usal_scsibus(usalp);          /* ASPI host adapter number             */
1101         s.SRB_Flags     = SRB_EVENT_NOTIFY;             /* Flags                                */
1102         s.SRB_Target    = usal_target(usalp);           /* Target's SCSI ID                     */
1103         s.SRB_Lun       = usal_lun(usalp);              /* Target's LUN number                  */
1104         s.SRB_PostProc  = (LPVOID)Event;                /* Post routine                         */
1105
1106         /*
1107          * Initiate SCSI command
1108          */
1109         Status = pfnSendASPI32Command((LPSRB)&s);
1110
1111         /*
1112          * Check status
1113          */
1114         if (Status == SS_PENDING) {
1115                 /*
1116                  * Wait till command completes
1117                  */
1118                 EventStatus = WaitForSingleObject(Event, INFINITE);
1119         }
1120
1121
1122         /**************************************************/
1123         /* Reset event to non-signaled state.             */
1124         /**************************************************/
1125
1126         if (EventStatus == WAIT_OBJECT_0) {
1127                 /*
1128                  * Clear event
1129                  */
1130                 ResetEvent(Event);
1131         }
1132
1133         /*
1134          * Close the event handle
1135          */
1136         CloseHandle(Event);
1137
1138         /*
1139          * Check condition
1140          */
1141         if (s.SRB_Status != SS_COMP) {
1142                 fprintf((FILE *)usalp->errfile,
1143                                         "ERROR! 0x%08X\n", s.SRB_Status);
1144
1145                 /*
1146                  * Indicate that error has occured
1147                  */
1148                 return (-1);
1149         }
1150
1151         if (usalp->debug > 0) {
1152                 fprintf((FILE *)usalp->errfile,
1153                                         "Reset SCSI device completed\n");
1154         }
1155
1156         /*
1157          * Everything went OK
1158          */
1159         return (0);
1160 }
1161
1162
1163 #ifdef DEBUG_WNTASPI
1164 static void
1165 DebugScsiSend(SCSI *usalp, SRB_ExecSCSICmd *s, int bDisplayBuffer)
1166 {
1167         int i;
1168
1169         fprintf((FILE *)usalp->errfile, "\n\nDebugScsiSend\n");
1170         fprintf((FILE *)usalp->errfile, "s->SRB_Cmd          = 0x%02x\n", s->SRB_Cmd);
1171         fprintf((FILE *)usalp->errfile, "s->SRB_HaId         = 0x%02x\n", s->SRB_HaId);
1172         fprintf((FILE *)usalp->errfile, "s->SRB_Flags        = 0x%02x\n", s->SRB_Flags);
1173         fprintf((FILE *)usalp->errfile, "s->SRB_Target       = 0x%02x\n", s->SRB_Target);
1174         fprintf((FILE *)usalp->errfile, "s->SRB_Lun          = 0x%02x\n", s->SRB_Lun);
1175         fprintf((FILE *)usalp->errfile, "s->SRB_BufLen       = 0x%02x\n", s->SRB_BufLen);
1176         fprintf((FILE *)usalp->errfile, "s->SRB_BufPointer   = %x\n",      s->SRB_BufPointer);
1177         fprintf((FILE *)usalp->errfile, "s->SRB_CDBLen       = 0x%02x\n", s->SRB_CDBLen);
1178         fprintf((FILE *)usalp->errfile, "s->SRB_SenseLen     = 0x%02x\n", s->SRB_SenseLen);
1179         fprintf((FILE *)usalp->errfile, "s->CDBByte          =");
1180         for (i = 0; i < min(s->SRB_CDBLen, 16); i++) {
1181                 fprintf((FILE *)usalp->errfile, " %02X ", s->CDBByte[i]);
1182         }
1183         fprintf((FILE *)usalp->errfile, "\n");
1184
1185         /*
1186         if (bDisplayBuffer != 0 && s->SRB_BufLen >= 8) {
1187
1188                 fprintf((FILE *)usalp->errfile, "s->SRB_BufPointer   =");
1189                 for (i = 0; i < 8; i++) {
1190                         fprintf((FILE *)usalp->errfile,
1191                                         " %02X ", ((char *)s->SRB_BufPointer)[i]);
1192                 }
1193                 fprintf((FILE *)usalp->errfile, "\n");
1194         }
1195 */
1196         fprintf((FILE *)usalp->errfile, "Debug done\n");
1197 }
1198 #endif
1199
1200 static void
1201 copy_sensedata(SRB_ExecSCSICmd *cp, struct usal_cmd *sp)
1202 {
1203         sp->sense_count = cp->SRB_SenseLen;
1204         if (sp->sense_count > sp->sense_len)
1205                 sp->sense_count = sp->sense_len;
1206
1207         memset(&sp->u_sense.Sense, 0x00, sizeof (sp->u_sense.Sense));
1208         memcpy(&sp->u_sense.Sense, cp->SenseArea, sp->sense_count);
1209
1210         sp->u_scb.cmd_scb[0] = cp->SRB_TargStat;
1211 }
1212
1213 /*
1214  * Set error flags
1215  */
1216 static void
1217 set_error(SRB_ExecSCSICmd *cp, struct usal_cmd *sp)
1218 {
1219         switch (cp->SRB_Status) {
1220
1221         case SS_COMP:                   /* 0x01 SRB completed without error  */
1222                 sp->error = SCG_NO_ERROR;
1223                 sp->ux_errno = 0;
1224                 break;
1225
1226         case SS_ERR:                    /* 0x04 SRB completed with error    */
1227                 /*
1228                  * If the SCSI Status byte is != 0, we definitely could send
1229                  * the command to the target. We signal NO transport error.
1230                  */
1231                 sp->error = SCG_NO_ERROR;
1232                 sp->ux_errno = EIO;
1233                 if (cp->SRB_TargStat)
1234                         break;
1235
1236         case SS_PENDING:                /* 0x00 SRB being processed         */
1237                 /*
1238                  * XXX Could SS_PENDING happen ???
1239                  */
1240         case SS_ABORTED:                /* 0x02 SRB aborted                 */
1241         case SS_ABORT_FAIL:             /* 0x03 Unable to abort SRB         */
1242         default:
1243                 sp->error = SCG_RETRYABLE;
1244                 sp->ux_errno = EIO;
1245                 break;
1246
1247         case SS_INVALID_CMD:            /* 0x80 Invalid ASPI command        */
1248         case SS_INVALID_HA:             /* 0x81 Invalid host adapter number */
1249         case SS_NO_DEVICE:              /* 0x82 SCSI device not installed   */
1250
1251         case SS_INVALID_SRB:            /* 0xE0 Invalid parameter set in SRB */
1252         case SS_ILLEGAL_MODE:           /* 0xE2 Unsupported Windows mode    */
1253         case SS_NO_ASPI:                /* 0xE3 No ASPI managers            */
1254         case SS_FAILED_INIT:            /* 0xE4 ASPI for windows failed init */
1255         case SS_MISMATCHED_COMPONENTS:  /* 0xE7 The DLLs/EXEs of ASPI don't */
1256                                         /*      version check               */
1257         case SS_NO_ADAPTERS:            /* 0xE8 No host adapters to manager */
1258
1259         case SS_ASPI_IS_SHUTDOWN:       /* 0xEA Call came to ASPI after     */
1260                                         /*      PROCESS_DETACH              */
1261         case SS_BAD_INSTALL:            /* 0xEB The DLL or other components */
1262                                         /*      are installed wrong         */
1263                 sp->error = SCG_FATAL;
1264                 sp->ux_errno = EINVAL;
1265                 break;
1266
1267 #ifdef  XXX
1268         case SS_OLD_MANAGER:            /* 0xE1 ASPI manager doesn't support */
1269                                         /*      windows                     */
1270 #endif
1271         case SS_BUFFER_ALIGN:           /* 0xE1 Buffer not aligned (replaces */
1272                                         /*      SS_OLD_MANAGER in Win32)    */
1273                 sp->error = SCG_FATAL;
1274                 sp->ux_errno = EFAULT;
1275                 break;
1276
1277         case SS_ASPI_IS_BUSY:           /* 0xE5 No resources available to   */
1278                                         /*      execute command             */
1279                 sp->error = SCG_RETRYABLE;
1280                 sp->ux_errno = EBUSY;
1281                 break;
1282
1283 #ifdef  XXX
1284         case SS_BUFFER_TO_BIG:          /* 0xE6 Buffer size too big to handle*/
1285 #endif
1286         case SS_BUFFER_TOO_BIG:         /* 0xE6 Correct spelling of 'too'   */
1287         case SS_INSUFFICIENT_RESOURCES: /* 0xE9 Couldn't allocate resources */
1288                                         /*      needed to init              */
1289                 sp->error = SCG_RETRYABLE;
1290                 sp->ux_errno = ENOMEM;
1291                 break;
1292         }
1293 }
1294
1295
1296 struct aspi_cmd {
1297         SRB_ExecSCSICmd         s;
1298         char                    pad[32];
1299 };
1300
1301 static int
1302 usalo_send(SCSI *usalp)
1303 {
1304         struct usal_cmd         *sp = usalp->scmd;
1305         DWORD                   Status = 0;
1306         DWORD                   EventStatus = WAIT_OBJECT_0;
1307         HANDLE                  Event    = NULL;
1308         struct aspi_cmd         ac;
1309         SRB_ExecSCSICmd         *s;
1310
1311         s = &ac.s;
1312
1313         /*
1314          * Check if ASPI library is loaded
1315          */
1316         if (DriverLoaded <= 0) {
1317                 errmsgno(EX_BAD, "error in usalo_send: ASPI driver not loaded.\n");
1318                 sp->error = SCG_FATAL;
1319                 return (0);
1320         }
1321
1322         if (usalp->fd < 0) {
1323                 sp->error = SCG_FATAL;
1324                 return (-1);
1325         }
1326
1327         /*
1328          * Initialize variables
1329          */
1330         sp->error               = SCG_NO_ERROR;
1331         sp->sense_count         = 0;
1332         sp->u_scb.cmd_scb[0]    = 0;
1333         sp->resid               = 0;
1334
1335         memset(&ac, 0, sizeof (ac));    /* Clear SRB structure */
1336
1337         /*
1338          * Check cbd_len > the maximum command pakket that can be handled by ASPI
1339          */
1340         if (sp->cdb_len > 16) {
1341                 sp->error = SCG_FATAL;
1342                 sp->ux_errno = EINVAL;
1343                 fprintf((FILE *)usalp->errfile,
1344                         "sp->cdb_len > sizeof (SRB_ExecSCSICmd.CDBByte). Fatal error in usalo_send, exiting...\n");
1345                 return (-1);
1346         }
1347         /*
1348          * copy cdrecord command into SRB
1349          */
1350         movebytes(&sp->cdb, &(s->CDBByte), sp->cdb_len);
1351
1352         Event = CreateEvent(NULL, TRUE, FALSE, NULL);
1353
1354         /*
1355          * Fill ASPI structure
1356          */
1357         s->SRB_Cmd       = SC_EXEC_SCSI_CMD;            /* SCSI Command                 */
1358         s->SRB_HaId      = usal_scsibus(usalp);         /* Host adapter number          */
1359         s->SRB_Flags     = SRB_EVENT_NOTIFY;            /* Flags                        */
1360         s->SRB_Target    = usal_target(usalp);          /* Target SCSI ID               */
1361         s->SRB_Lun       = usal_lun(usalp);             /* Target SCSI LUN              */
1362         s->SRB_BufLen    = sp->size;                    /* # of bytes transferred       */
1363         s->SRB_BufPointer = sp->addr;                   /* pointer to data buffer       */
1364         s->SRB_CDBLen    = sp->cdb_len;                 /* SCSI command length          */
1365         s->SRB_PostProc  = Event;                       /* Post proc event              */
1366         if (UsingSPTI)
1367                 s->SRB_SenseLen = SENSE_LEN_SPTI;       /* Length of sense buffer, SPTI returns SenseInfoLength */
1368         else
1369                 s->SRB_SenseLen = SENSE_LEN;            /* fixed length 14 for ASPI */
1370         /*
1371          * Do we receive data from this ASPI command?
1372          */
1373         if (sp->flags & SCG_RECV_DATA) {
1374
1375                 s->SRB_Flags |= SRB_DIR_IN;
1376         } else {
1377                 /*
1378                  * Set direction to output
1379                  */
1380                 if (sp->size > 0) {
1381                         s->SRB_Flags |= SRB_DIR_OUT;
1382                 }
1383         }
1384
1385 #ifdef DEBUG_WNTASPI
1386         /*
1387          * Dump some debug information when enabled
1388          */
1389         DebugScsiSend(usalp, s, TRUE);
1390 /*      DebugScsiSend(usalp, s, (s->SRB_Flags&SRB_DIR_OUT) == SRB_DIR_OUT);*/
1391 #endif
1392
1393         /*
1394          * ------------ Send SCSI command --------------------------
1395          */
1396
1397         ResetEvent(Event);                      /* Clear event handle       */
1398         if (UsingSPTI) {
1399 #ifdef _DEBUG_SCSIPT
1400                 usalp_errfile = (FILE *)usalp->errfile;
1401 #endif
1402                 Status = SPTIExecSCSICommand(s, sp->timeout, FALSE);
1403         }
1404         else
1405                 Status = pfnSendASPI32Command((LPSRB)s); /* Initiate SCSI command */
1406         if (Status == SS_PENDING) {             /* If in progress           */
1407                 /*
1408                  * Wait untill command completes, or times out.
1409                  */
1410                 EventStatus = WaitForSingleObject(Event, sp->timeout*1000L);
1411 /*              EventStatus = WaitForSingleObject(Event, 10L);*/
1412
1413                 if (EventStatus == WAIT_OBJECT_0)
1414                         ResetEvent(Event);      /* Clear event, time out    */
1415
1416                 if (s->SRB_Status == SS_PENDING) { /* Check if we got a timeout */
1417                         if (usalp->debug > 0) {
1418                                 fprintf((FILE *)usalp->errfile,
1419                                                 "Timeout....\n");
1420                         }
1421                         scsiabort(usalp, s);
1422                         ResetEvent(Event);      /* Clear event, time out    */
1423                         CloseHandle(Event);     /* Close the event handle   */
1424
1425                         sp->error = SCG_TIMEOUT;
1426                         return (1);             /* Return error             */
1427                 }
1428         }
1429         CloseHandle(Event);                     /* Close the event handle   */
1430
1431         /*
1432          * Check ASPI command status
1433          */
1434         if (s->SRB_Status != SS_COMP) {
1435                 if (usalp->debug > 0) {
1436                         fprintf((FILE *)usalp->errfile,
1437                                 "Error in usalo_send: s->SRB_Status is 0x%x\n", s->SRB_Status);
1438                 }
1439
1440                 set_error(s, sp);               /* Set error flags          */
1441                 copy_sensedata(s, sp);          /* Copy sense and status    */
1442
1443                 if (usalp->debug > 0) {
1444                         fprintf((FILE *)usalp->errfile,
1445                                 "Mapped to: error %d errno: %d\n", sp->error, sp->ux_errno);
1446                 }
1447                 return (1);
1448         }
1449
1450         /*
1451          * Return success
1452          */
1453         return (0);
1454 }
1455
1456 /***************************************************************************
1457  *                                                                         *
1458  *  BOOL open_driver()                                                     *
1459  *                                                                         *
1460  *  Opens the ASPI Router device driver and sets device_handle.            *
1461  *  Returns:                                                               *
1462  *    TRUE - Success                                                       *
1463  *    FALSE - Unsuccessful opening of device driver                        *
1464  *                                                                         *
1465  *  Preconditions: ASPI Router driver has be loaded                        *
1466  *                                                                         *
1467  ***************************************************************************/
1468 static BOOL
1469 open_driver(SCSI *usalp)
1470 {
1471         DWORD   astatus;
1472         BYTE    HACount;
1473         BYTE    ASPIStatus;
1474         int     i;
1475
1476 #ifdef DEBUG_WNTASPI
1477         fprintf((FILE *)usalp->errfile, "enter open_driver\n");
1478 #endif
1479
1480         /*
1481          * Check if ASPI library is already loaded yet
1482          */
1483         if (DriverLoaded > 0) {
1484                 DriverLoaded++;
1485                 return (TRUE);
1486         }
1487
1488         /*
1489          * Load the ASPI library or SPTI
1490          */
1491 #ifdef _DEBUG_SCSIPT
1492         usalp_errfile = (FILE *)usalp->errfile;
1493 #endif
1494 #ifdef  PREFER_SPTI
1495         if (UsingSPTI)
1496                 if (InitSCSIPT(usalp) > 0) DriverLoaded++;
1497 #endif
1498 #ifdef  PREFER_SPTI
1499         if ((!UsingSPTI || !ForceAccess) && DriverLoaded <= 0) {
1500 #else
1501         if (!UsingSPTI || !ForceAccess) {
1502 #endif
1503                 if (load_aspi(usalp)) {
1504                         DriverLoaded++;
1505                         UsingSPTI = FALSE;
1506                 }
1507         }
1508
1509 #ifndef PREFER_SPTI
1510         if ((UsingSPTI || !ForceAccess) && DriverLoaded <= 0)
1511                 if (InitSCSIPT(usalp) > 0)
1512                         DriverLoaded++;
1513 #endif  /*PREFER_SPTI*/
1514
1515         if (DriverLoaded <= 0) {
1516                 if (UsingSPTI) {
1517                         if (errno == 0)
1518                                 errno = ENOSYS;
1519                 }
1520                 fprintf((FILE *)usalp->errfile, "Can not load %s driver! ",
1521                                                 UsingSPTI ? "SPTI":"ASPI");
1522                 return (FALSE);
1523         }
1524
1525         if (UsingSPTI) {
1526                 if (usalp->debug > 0)
1527                         fprintf((FILE *)usalp->errfile, "using SPTI Transport\n");
1528
1529                 if (!sptiglobal.numAdapters)
1530                         astatus = (DWORD)(MAKEWORD(0, SS_NO_ADAPTERS));
1531                 else
1532                         astatus = (DWORD)(MAKEWORD(sptiglobal.numAdapters, SS_COMP));
1533         } else {
1534                 astatus = pfnGetASPI32SupportInfo();
1535         }
1536
1537         ASPIStatus = HIBYTE(LOWORD(astatus));
1538         HACount    = LOBYTE(LOWORD(astatus));
1539
1540         if (usalp->debug > 0) {
1541                 fprintf((FILE *)usalp->errfile,
1542                         "open_driver %lX HostASPIStatus=0x%x HACount=0x%x\n", astatus, ASPIStatus, HACount);
1543         }
1544
1545         if (ASPIStatus != SS_COMP && ASPIStatus != SS_NO_ADAPTERS) {
1546                 fprintf((FILE *)usalp->errfile, "Could not find any host adapters\n");
1547                 fprintf((FILE *)usalp->errfile, "ASPIStatus == 0x%02X", ASPIStatus);
1548                 return (FALSE);
1549         }
1550         busses = HACount;
1551
1552 #ifdef DEBUG_WNTASPI
1553         fprintf((FILE *)usalp->errfile, "open_driver HostASPIStatus=0x%x HACount=0x%x\n", ASPIStatus, HACount);
1554         fprintf((FILE *)usalp->errfile, "leaving open_driver\n");
1555 #endif
1556
1557         for (i = 0; i < busses; i++) {
1558                 SRB_HAInquiry   s;
1559
1560                 ha_inquiry(usalp, i, &s);
1561         }
1562
1563         /*
1564          * Indicate that library loaded/initialized properly
1565          */
1566         return (TRUE);
1567 }
1568
1569 static BOOL
1570 load_aspi(SCSI *usalp)
1571 {
1572 #ifdef  __CYGWIN32__
1573         hAspiLib = dlopen("WNASPI32", RTLD_NOW);
1574 #else
1575         hAspiLib = LoadLibrary("WNASPI32");
1576 #endif
1577         /*
1578          * Check if ASPI library is loaded correctly
1579          */
1580         if (hAspiLib == NULL) {
1581 #ifdef  not_done_later
1582                 fprintf((FILE *)usalp->errfile, "Can not load ASPI driver! ");
1583 #endif
1584                 return (FALSE);
1585         }
1586
1587         /*
1588          * Get a pointer to GetASPI32SupportInfo function
1589          * and a pointer to SendASPI32Command function
1590          */
1591 #ifdef  __CYGWIN32__
1592         pfnGetASPI32SupportInfo = (DWORD(*)(void))dlsym(hAspiLib, "GetASPI32SupportInfo");
1593         pfnSendASPI32Command = (DWORD(*)(LPSRB))dlsym(hAspiLib, "SendASPI32Command");
1594 #else
1595         pfnGetASPI32SupportInfo = (DWORD(*)(void))GetProcAddress(hAspiLib, "GetASPI32SupportInfo");
1596         pfnSendASPI32Command = (DWORD(*)(LPSRB))GetProcAddress(hAspiLib, "SendASPI32Command");
1597 #endif
1598
1599         if ((pfnGetASPI32SupportInfo == NULL) || (pfnSendASPI32Command == NULL)) {
1600                 fprintf((FILE *)usalp->errfile,
1601                                 "ASPI function not found in library! ");
1602                 return (FALSE);
1603         }
1604
1605         /*
1606          * The following functions are currently not used by libusal.
1607          * If we start to use them, we need to check whether the founctions
1608          * could be found in the ASPI library that just has been loaded.
1609          */
1610 #ifdef  __CYGWIN32__
1611         pfnGetASPI32Buffer = (BOOL(*)(PASPI32BUFF))dlsym(hAspiLib, "GetASPI32Buffer");
1612         pfnFreeASPI32Buffer = (BOOL(*)(PASPI32BUFF))dlsym(hAspiLib, "FreeASPI32Buffer");
1613         pfnTranslateASPI32Address = (BOOL(*)(PDWORD, PDWORD))dlsym(hAspiLib, "TranslateASPI32Address");
1614 #else
1615         pfnGetASPI32Buffer = (BOOL(*)(PASPI32BUFF))GetProcAddress(hAspiLib, "GetASPI32Buffer");
1616         pfnFreeASPI32Buffer = (BOOL(*)(PASPI32BUFF))GetProcAddress(hAspiLib, "FreeASPI32Buffer");
1617         pfnTranslateASPI32Address = (BOOL(*)(PDWORD, PDWORD))GetProcAddress(hAspiLib, "TranslateASPI32Address");
1618 #endif
1619         return (TRUE);
1620 }
1621
1622 /***************************************************************************
1623  *                                                                         *
1624  *  BOOL close_driver()                                                    *
1625  *                                                                         *
1626  *  Closes the device driver                                               *
1627  *  Returns:                                                               *
1628  *    TRUE - Success                                                       *
1629  *    FALSE - Unsuccessful closing of device driver                        *
1630  *                                                                         *
1631  *  Preconditions: ASPI Router driver has be opened with open_driver       *
1632  *                                                                         *
1633  ***************************************************************************/
1634 static BOOL
1635 close_driver()
1636 {
1637         if (--DriverLoaded > 0)
1638                 return (TRUE);
1639         /*
1640          * If library is loaded
1641          */
1642         DeinitSCSIPT();
1643         /*
1644          * Clear all variables
1645          */
1646         if (hAspiLib) {
1647                 pfnGetASPI32SupportInfo = NULL;
1648                 pfnSendASPI32Command    = NULL;
1649                 pfnGetASPI32Buffer      = NULL;
1650                 pfnFreeASPI32Buffer     = NULL;
1651                 pfnTranslateASPI32Address = NULL;
1652
1653                 /*
1654                  * Free ASPI library, we do not need it any longer
1655                  */
1656 #ifdef  __CYGWIN32__
1657                 dlclose(hAspiLib);
1658 #else
1659                 FreeLibrary(hAspiLib);
1660 #endif
1661                 hAspiLib = NULL;
1662         }
1663
1664         /*
1665          * Indicate that shutdown has been finished properly
1666          */
1667         return (TRUE);
1668 }
1669
1670 static int
1671 ha_inquiry(SCSI *usalp, int id, SRB_HAInquiry *ip)
1672 {
1673         DWORD           Status;
1674
1675         ip->SRB_Cmd      = SC_HA_INQUIRY;
1676         ip->SRB_HaId     = id;
1677         ip->SRB_Flags    = 0;
1678         ip->SRB_Hdr_Rsvd = 0;
1679
1680         if (UsingSPTI)
1681                 Status = SPTIHandleHaInquiry(ip);
1682         else
1683                 Status = pfnSendASPI32Command((LPSRB)ip);
1684
1685         if (usalp->debug > 0) {
1686                 fprintf((FILE *)usalp->errfile, "Status : %ld\n",       Status);
1687                 fprintf((FILE *)usalp->errfile, "hacount: %d\n", ip->HA_Count);
1688                 fprintf((FILE *)usalp->errfile, "SCSI id: %d\n", ip->HA_SCSI_ID);
1689                 fprintf((FILE *)usalp->errfile, "Manager: '%.16s'\n", ip->HA_ManagerId);
1690                 fprintf((FILE *)usalp->errfile, "Identif: '%.16s'\n", ip->HA_Identifier);
1691                 usal_prbytes("Unique:", ip->HA_Unique, 16);
1692         }
1693         if (ip->SRB_Status != SS_COMP)
1694                 return (-1);
1695         return (0);
1696 }
1697
1698 #ifdef  __USED__
1699 static int
1700 resetSCSIBus(SCSI *usalp)
1701 {
1702         DWORD                   Status;
1703         HANDLE                  Event;
1704         SRB_BusDeviceReset      s;
1705
1706         if (UsingSPTI) {
1707                 fprintf((FILE *)usalp->errfile,
1708                                         "Reset SCSI bus not implemented with SPTI\n");
1709                 return (FALSE);
1710         }
1711
1712         fprintf((FILE *)usalp->errfile, "Attempting to reset SCSI bus\n");
1713
1714         Event = CreateEvent(NULL, TRUE, FALSE, NULL);
1715
1716         memset(&s, 0, sizeof (s));      /* Clear SRB_BesDeviceReset structure */
1717
1718         /*
1719          * Set structure variables
1720          */
1721         s.SRB_Cmd = SC_RESET_DEV;
1722         s.SRB_PostProc = (LPVOID)Event;
1723
1724         /*
1725          * Clear event
1726          */
1727         ResetEvent(Event);
1728
1729         /*
1730          * Initiate SCSI command
1731          */
1732         Status = pfnSendASPI32Command((LPSRB)&s);
1733
1734         /*
1735          * Check status
1736          */
1737         if (Status == SS_PENDING) {
1738                 /*
1739                  * Wait till command completes
1740                  */
1741                 WaitForSingleObject(Event, INFINITE);
1742         }
1743
1744         /*
1745          * Close the event handle
1746          */
1747         CloseHandle(Event);
1748
1749         /*
1750          * Check condition
1751          */
1752         if (s.SRB_Status != SS_COMP) {
1753                 fprintf((FILE *)usalp->errfile, "ERROR  0x%08X\n", s.SRB_Status);
1754
1755                 /*
1756                  * Indicate that error has occured
1757                  */
1758                 return (FALSE);
1759         }
1760
1761         /*
1762          * Everything went OK
1763          */
1764         return (TRUE);
1765 }
1766 #endif  /* __USED__ */
1767
1768 static int
1769 scsiabort(SCSI *usalp, SRB_ExecSCSICmd *sp)
1770 {
1771         DWORD                   Status = 0;
1772         SRB_Abort               s;
1773
1774         if (UsingSPTI) {
1775                 fprintf((FILE *)usalp->errfile,
1776                                         "Abort SCSI not implemented with SPTI\n");
1777                 return (FALSE);
1778         }
1779
1780         if (usalp->debug > 0) {
1781                 fprintf((FILE *)usalp->errfile,
1782                                 "Attempting to abort SCSI command\n");
1783         }
1784
1785         /*
1786          * Check if ASPI library is loaded
1787          */
1788         if (DriverLoaded <= 0) {
1789                 fprintf((FILE *)usalp->errfile,
1790                                 "error in scsiabort: ASPI driver not loaded !\n");
1791                 return (FALSE);
1792         }
1793
1794         /*
1795          * Set structure variables
1796          */
1797         s.SRB_Cmd       = SC_ABORT_SRB;                 /* ASPI command code = SC_ABORT_SRB     */
1798         s.SRB_HaId      = usal_scsibus(usalp);          /* ASPI host adapter number             */
1799         s.SRB_Flags     = 0;                            /* Flags                                */
1800         s.SRB_ToAbort   = (LPSRB)&sp;                   /* sp                                   */
1801
1802         /*
1803          * Initiate SCSI abort
1804          */
1805         Status = pfnSendASPI32Command((LPSRB)&s);
1806
1807         /*
1808          * Check condition
1809          */
1810         if (s.SRB_Status != SS_COMP) {
1811                 fprintf((FILE *)usalp->errfile, "Abort ERROR! 0x%08X\n", s.SRB_Status);
1812
1813                 /*
1814                  * Indicate that error has occured
1815                  */
1816                 return (FALSE);
1817         }
1818
1819         if (usalp->debug > 0)
1820                 fprintf((FILE *)usalp->errfile, "Abort SCSI command completed\n");
1821
1822         /*
1823          * Everything went OK
1824          */
1825         return (TRUE);
1826 }
1827
1828
1829 #define HAVE_NAT_NAMES
1830 static char * usalo_natname(SCSI *usalp, int busno, int tgt, int tlun) {
1831         int i;
1832         static char name[3];
1833         printf("hm, %d, %d, %d\n", busno, tgt, tlun);
1834         if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN)
1835                 return "BADID";
1836         for (i = NUM_FLOPPY_DRIVES; i < NUM_MAX_NTSCSI_DRIVES; i++) {
1837                 if(sptiglobal.drive[i].bUsed &&
1838                                 tlun == sptiglobal.drive[i].lun &&
1839                                 tgt == sptiglobal.drive[i].tgt && 
1840                                 busno == sptiglobal.drive[i].ha)
1841                 {
1842                         snprintf(name, 3, "%c:", 'A'+sptiglobal.drive[i].driveLetter);
1843                         return name;
1844                 }
1845         }
1846         return "BADID";
1847 }
1848