17 #include "debugtools.h"
21 DEFAULT_DEBUG_CHANNEL(aspi
);
24 * 1) Residual byte length reporting not handled
25 * 2) Make this code re-entrant for multithreading
26 * -- Added CriticalSection to OpenDevices function
27 * 3) Only linux supported so far
28 * 4) Leaves sg devices open. This may or may not be okay. A better solution
29 * would be to close the file descriptors when the thread/process using
30 * them no longer needs them.
35 static ASPI_DEVICE_INFO
*ASPI_open_devices
= NULL
;
36 static CRITICAL_SECTION ASPI_CritSection
;
38 #endif /* defined(linux) */
41 BOOL WINAPI
WNASPI32_LibMain(HINSTANCE hInstDLL
, DWORD fdwReason
, LPVOID fImpLoad
)
44 static BOOL bInitDone
=FALSE
;
46 TRACE("0x%x 0x%1x %p\n", hInstDLL
, fdwReason
, fImpLoad
);
50 case DLL_PROCESS_ATTACH
:
51 /* Create instance data */
54 /* Initialize global stuff just once */
55 InitializeCriticalSection(&ASPI_CritSection
);
59 case DLL_PROCESS_DETACH
:
60 /* Destroy instance data */
62 case DLL_THREAD_ATTACH
:
63 case DLL_THREAD_DETACH
:
67 #else /* defined(linux) */
69 #endif /* defined(linux) */
75 ASPI_OpenDevice(SRB_ExecSCSICmd
*prb
)
80 ASPI_DEVICE_INFO
*curr
;
82 /* search list of devices to see if we've opened it already.
83 * There is not an explicit open/close in ASPI land, so hopefully
84 * keeping a device open won't be a problem.
87 EnterCriticalSection(&ASPI_CritSection
);
88 for (curr
= ASPI_open_devices
; curr
; curr
= curr
->next
) {
89 if (curr
->hostId
== prb
->SRB_HaId
&&
90 curr
->target
== prb
->SRB_Target
&&
91 curr
->lun
== prb
->SRB_Lun
) {
92 LeaveCriticalSection(&ASPI_CritSection
);
96 LeaveCriticalSection(&ASPI_CritSection
);
98 /* device wasn't cached, go ahead and open it */
99 sprintf(idstr
, "scsi c%1dt%1dd%1d", prb
->SRB_HaId
, prb
->SRB_Target
, prb
->SRB_Lun
);
101 if (!PROFILE_GetWineIniString(idstr
, "Device", "", device_str
, sizeof(device_str
))) {
102 TRACE("Trying to open unlisted scsi device %s\n", idstr
);
106 TRACE("Opening device %s=%s\n", idstr
, device_str
);
108 fd
= open(device_str
, O_RDWR
);
110 int save_error
= errno
;
112 ERR("Error opening device %s, error '%s'\n", device_str
, strerror(save_error
));
114 ERR("Error opening device %s, error %d\n", device_str
, save_error
);
119 /* device is now open */
120 curr
= HeapAlloc( SystemHeap
, 0, sizeof(ASPI_DEVICE_INFO
) );
122 curr
->hostId
= prb
->SRB_HaId
;
123 curr
->target
= prb
->SRB_Target
;
124 curr
->lun
= prb
->SRB_Lun
;
126 /* insert new record at beginning of open device list */
127 EnterCriticalSection(&ASPI_CritSection
);
128 curr
->next
= ASPI_open_devices
;
129 ASPI_open_devices
= curr
;
130 LeaveCriticalSection(&ASPI_CritSection
);
136 ASPI_DebugPrintCmd(SRB_ExecSCSICmd
*prb
)
142 switch (prb
->CDBByte
[0]) {
145 TRACE("\tEVPD: %d\n", prb
->CDBByte
[1] & 1);
146 TRACE("\tLUN: %d\n", (prb
->CDBByte
[1] & 0xc) >> 1);
147 TRACE("\tPAGE CODE: %d\n", prb
->CDBByte
[2]);
148 TRACE("\tALLOCATION LENGTH: %d\n", prb
->CDBByte
[4]);
149 TRACE("\tCONTROL: %d\n", prb
->CDBByte
[5]);
153 TRACE("Transfer Length: %d\n", prb
->CDBByte
[4]);
157 TRACE("Host Adapter: %d\n", prb
->SRB_HaId
);
158 TRACE("Flags: %d\n", prb
->SRB_Flags
);
159 if (TARGET_TO_HOST(prb
)) {
160 TRACE("\tData transfer: Target to host. Length checked.\n");
162 else if (HOST_TO_TARGET(prb
)) {
163 TRACE("\tData transfer: Host to target. Length checked.\n");
165 else if (NO_DATA_TRANSFERED(prb
)) {
166 TRACE("\tData transfer: none\n");
169 WARN("\tTransfer by scsi cmd. Length not checked.\n");
172 TRACE("\tResidual byte length reporting %s\n", prb
->SRB_Flags
& 0x4 ? "enabled" : "disabled");
173 TRACE("\tLinking %s\n", prb
->SRB_Flags
& 0x2 ? "enabled" : "disabled");
174 TRACE("\tPosting %s\n", prb
->SRB_Flags
& 0x1 ? "enabled" : "disabled");
175 TRACE("Target: %d\n", prb
->SRB_Target
);
176 TRACE("Lun: %d\n", prb
->SRB_Lun
);
177 TRACE("BufLen: %ld\n", prb
->SRB_BufLen
);
178 TRACE("SenseLen: %d\n", prb
->SRB_SenseLen
);
179 TRACE("BufPtr: %p\n", prb
->SRB_BufPointer
);
180 TRACE("CDB Length: %d\n", prb
->SRB_CDBLen
);
181 TRACE("POST Proc: %lx\n", (DWORD
) prb
->SRB_PostProc
);
182 cdb
= &prb
->CDBByte
[0];
183 cmd
= prb
->CDBByte
[0];
186 DPRINTF("CDB buffer[");
187 for (i
= 0; i
< prb
->SRB_CDBLen
; i
++) {
188 if (i
!= 0) DPRINTF(",");
189 DPRINTF("%02x", *cdb
++);
196 ASPI_PrintSenseArea(SRB_ExecSCSICmd
*prb
)
203 cdb
= &prb
->CDBByte
[16];
204 DPRINTF("SenseArea[");
205 for (i
= 0; i
< prb
->SRB_SenseLen
; i
++) {
207 DPRINTF("%02x", *cdb
++);
214 ASPI_DebugPrintResult(SRB_ExecSCSICmd
*prb
)
217 TRACE("SRB_Status: %x\n", prb
->SRB_Status
);
218 TRACE("SRB_HaStat: %x\n", prb
->SRB_HaStat
);
219 TRACE("SRB_TargStat: %x\n", prb
->SRB_TargStat
);
220 switch (prb
->CDBByte
[0]) {
222 TRACE("Vendor: '%s'\n", prb
->SRB_BufPointer
+ INQUIRY_VENDOR
);
224 case CMD_TEST_UNIT_READY
:
225 ASPI_PrintSenseArea(prb
);
231 ASPI_ExecScsiCmd(SRB_ExecSCSICmd
*lpPRB
)
233 struct sg_header
*sg_hd
, *sg_reply_hdr
;
239 ASPI_DebugPrintCmd(lpPRB
);
241 fd
= ASPI_OpenDevice(lpPRB
);
243 ERR("Failed: could not open device c%01dt%01dd%01d. Device permissions !?\n",
244 lpPRB
->SRB_HaId
,lpPRB
->SRB_Target
,lpPRB
->SRB_Lun
);
245 lpPRB
->SRB_Status
= SS_NO_DEVICE
;
252 lpPRB
->SRB_Status
= SS_PENDING
;
254 if (!lpPRB
->SRB_CDBLen
) {
255 WARN("Failed: lpPRB->SRB_CDBLen = 0.\n");
256 lpPRB
->SRB_Status
= SS_ERR
;
260 /* build up sg_header + scsi cmd */
261 if (HOST_TO_TARGET(lpPRB
)) {
262 /* send header, command, and then data */
263 in_len
= SCSI_OFF
+ lpPRB
->SRB_CDBLen
+ lpPRB
->SRB_BufLen
;
264 sg_hd
= (struct sg_header
*) HeapAlloc(GetProcessHeap(), 0, in_len
);
265 memset(sg_hd
, 0, SCSI_OFF
);
266 memcpy(sg_hd
+ 1, &lpPRB
->CDBByte
[0], lpPRB
->SRB_CDBLen
);
267 if (lpPRB
->SRB_BufLen
) {
268 memcpy(((BYTE
*) sg_hd
) + SCSI_OFF
+ lpPRB
->SRB_CDBLen
, lpPRB
->SRB_BufPointer
, lpPRB
->SRB_BufLen
);
272 /* send header and command - no data */
273 in_len
= SCSI_OFF
+ lpPRB
->SRB_CDBLen
;
274 sg_hd
= (struct sg_header
*) HeapAlloc(GetProcessHeap(), 0, in_len
);
275 memset(sg_hd
, 0, SCSI_OFF
);
276 memcpy(sg_hd
+ 1, &lpPRB
->CDBByte
[0], lpPRB
->SRB_CDBLen
);
279 if (TARGET_TO_HOST(lpPRB
)) {
280 out_len
= SCSI_OFF
+ lpPRB
->SRB_BufLen
;
281 sg_reply_hdr
= (struct sg_header
*) HeapAlloc(GetProcessHeap(), 0, out_len
);
282 memset(sg_reply_hdr
, 0, SCSI_OFF
);
283 sg_hd
->reply_len
= out_len
;
287 sg_reply_hdr
= (struct sg_header
*) HeapAlloc(GetProcessHeap(), 0, out_len
);
288 memset(sg_reply_hdr
, 0, SCSI_OFF
);
289 sg_hd
->reply_len
= out_len
;
292 status
= write(fd
, sg_hd
, in_len
);
293 if (status
< 0 || status
!= in_len
) {
294 int save_error
= errno
;
296 WARN("Not enough bytes written to scsi device bytes=%d .. %d\n", in_len
, status
);
298 if (save_error
== ENOMEM
) {
299 MESSAGE("ASPI: Linux generic scsi driver\n You probably need to re-compile your kernel with a larger SG_BIG_BUFF value (sg.h)\n Suggest 130560\n");
302 WARN("error:= '%s'\n", strerror(save_error
));
304 WARN("error:= %d\n", save_error
);
310 status
= read(fd
, sg_reply_hdr
, out_len
);
311 if (status
< 0 || status
!= out_len
) {
312 WARN("not enough bytes read from scsi device%d\n", status
);
316 if (sg_reply_hdr
->result
!= 0) {
317 error_code
= sg_reply_hdr
->result
;
318 WARN("reply header error (%d)\n", sg_reply_hdr
->result
);
322 if (TARGET_TO_HOST(lpPRB
) && lpPRB
->SRB_BufLen
) {
323 memcpy(lpPRB
->SRB_BufPointer
, sg_reply_hdr
+ 1, lpPRB
->SRB_BufLen
);
326 /* copy in sense buffer to amount that is available in client */
327 if (lpPRB
->SRB_SenseLen
) {
328 int sense_len
= lpPRB
->SRB_SenseLen
;
329 if (lpPRB
->SRB_SenseLen
> 16)
332 /* CDB is fixed in WNASPI32 */
333 memcpy(&lpPRB
->CDBByte
[16], &sg_reply_hdr
->sense_buffer
[0], sense_len
);
335 TRACE("CDB is %d bytes long\n", lpPRB
->SRB_CDBLen
);
336 ASPI_PrintSenseArea(lpPRB
);
339 lpPRB
->SRB_Status
= SS_COMP
;
340 lpPRB
->SRB_HaStat
= HASTAT_OK
;
341 lpPRB
->SRB_TargStat
= sg_reply_hdr
->target_status
<< 1;
343 /* FIXME: Should this be != 0 maybe? */
344 if( lpPRB
->SRB_TargStat
== 2 )
345 lpPRB
->SRB_Status
= SS_ERR
;
347 ASPI_DebugPrintResult(lpPRB
);
350 if (lpPRB
->SRB_PostProc
) {
351 if (ASPI_POSTING(lpPRB
)) {
352 TRACE("Post Routine (%lx) called\n", (DWORD
) lpPRB
->SRB_PostProc
);
353 (*lpPRB
->SRB_PostProc
)(lpPRB
);
356 if (lpPRB
->SRB_Flags
& SRB_EVENT_NOTIFY
) {
357 TRACE("Setting event %04x\n", (HANDLE
)lpPRB
->SRB_PostProc
);
358 SetEvent((HANDLE
)lpPRB
->SRB_PostProc
); /* FIXME: correct ? */
361 HeapFree(GetProcessHeap(), 0, sg_reply_hdr
);
362 HeapFree(GetProcessHeap(), 0, sg_hd
);
364 /* In real WNASPI32 stuff really is always pending because ASPI does things
365 in the background, but we are not doing that (yet) */
368 if (error_code
== EBUSY
) {
369 lpPRB
->SRB_Status
= SS_ASPI_IS_BUSY
;
370 TRACE("Device busy\n");
374 lpPRB
->SRB_Status
= SS_ERR
;
377 /* I'm not sure exactly error codes work here
378 * We probably should set lpPRB->SRB_TargStat, SRB_HaStat ?
380 WARN("error_exit\n");
381 HeapFree(GetProcessHeap(), 0, sg_reply_hdr
);
382 HeapFree(GetProcessHeap(), 0, sg_hd
);
383 return lpPRB
->SRB_Status
;
386 #endif /* defined(linux) */
389 /*******************************************************************
390 * GetASPI32SupportInfo32 [WNASPI32.0]
392 * Checks if the ASPI subsystem is initialized correctly.
396 * HIBYTE of LOWORD: status (SS_COMP or SS_FAILED_INIT)
397 * LOBYTE of LOWORD: # of host adapters.
399 DWORD WINAPI
GetASPI32SupportInfo()
401 return ((SS_COMP
<< 8) | 1); /* FIXME: get # of host adapters installed */
405 /***********************************************************************
406 * SendASPI32Command32 (WNASPI32.1)
408 DWORD __cdecl
SendASPI32Command(LPSRB lpSRB
)
411 switch (lpSRB
->common
.SRB_Cmd
) {
413 lpSRB
->inquiry
.SRB_Status
= SS_COMP
; /* completed successfully */
414 lpSRB
->inquiry
.HA_Count
= 1; /* not always */
415 lpSRB
->inquiry
.HA_SCSI_ID
= 7; /* not always ID 7 */
416 strcat(lpSRB
->inquiry
.HA_ManagerId
, "ASPI for WIN32"); /* max 15 chars, don't change */
417 strcat(lpSRB
->inquiry
.HA_Identifier
, "Wine host"); /* FIXME: return host adapter name */
418 memset(lpSRB
->inquiry
.HA_Unique
, 0, 16); /* default HA_Unique content */
419 lpSRB
->inquiry
.HA_Unique
[6] = 0x02; /* Maximum Transfer Length (128K, Byte> 4-7) */
420 FIXME("ASPI: Partially implemented SC_HA_INQUIRY for adapter %d.\n", lpSRB
->inquiry
.SRB_HaId
);
422 case SC_GET_DEV_TYPE
: {
423 /* FIXME: We should return SS_NO_DEVICE if the device is not configured */
424 /* FIXME: We should return SS_INVALID_HA if HostAdapter!=0 */
428 memset(&tmpsrb
,0,sizeof(tmpsrb
));
430 tmpsrb
.cmd
.SRB_Cmd
= SC_EXEC_SCSI_CMD
;
431 #define X(x) tmpsrb.cmd.SRB_##x = lpSRB->devtype.SRB_##x
432 X(Status
);X(HaId
);X(Flags
);X(Target
);X(Lun
);
434 tmpsrb
.cmd
.SRB_BufLen
= sizeof(inqbuf
);
435 tmpsrb
.cmd
.SRB_Flags
= 8;/*target->host data. FIXME: anything more?*/
436 tmpsrb
.cmd
.SRB_BufPointer
= inqbuf
;
437 tmpsrb
.cmd
.CDBByte
[0] = 0x12; /* INQUIRY */
438 tmpsrb
.cmd
.CDBByte
[4] = sizeof(inqbuf
);
439 tmpsrb
.cmd
.SRB_CDBLen
= 6;
440 ASPI_ExecScsiCmd(&tmpsrb
.cmd
);
441 #define X(x) lpSRB->devtype.SRB_##x = tmpsrb.cmd.SRB_##x
444 lpSRB
->devtype
.SRB_DeviceType
= inqbuf
[0]&0x1f;
445 TRACE("returning devicetype %d for target %d\n",inqbuf
[0]&0x1f,tmpsrb
.cmd
.SRB_Target
);
448 case SC_EXEC_SCSI_CMD
:
449 return ASPI_ExecScsiCmd(&lpSRB
->cmd
);
452 FIXME("Not implemented SC_ABORT_SRB\n");
455 FIXME("Not implemented SC_RESET_DEV\n");
457 #ifdef SC_GET_DISK_INFO
458 case SC_GET_DISK_INFO
:
459 /* NT Doesn't implement this either.. so don't feel bad */
460 WARN("Not implemented SC_GET_DISK_INFO\n");
464 WARN("Unknown command %d\n", lpSRB
->common
.SRB_Cmd
);
466 return SS_INVALID_SRB
;
468 return SS_INVALID_SRB
;
473 /***********************************************************************
474 * GetASPI32DLLVersion32 (WNASPI32.3)
477 DWORD WINAPI
GetASPI32DLLVersion()