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