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