Moved SystemHeap allocations to the process heap.
[wine.git] / dlls / wnaspi32 / winaspi32.c
blobec226df7a074bf05882198df36b73aa4453cee3a
1 #include "config.h"
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <memory.h>
10 #include <unistd.h>
12 #include "winbase.h"
13 #include "aspi.h"
14 #include "wnaspi32.h"
15 #include "options.h"
16 #include "heap.h"
17 #include "debugtools.h"
18 #include "ldt.h"
19 #include "callback.h"
21 DEFAULT_DEBUG_CHANNEL(aspi);
23 /* FIXME!
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.
33 #ifdef linux
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)
43 #ifdef linux
44 static BOOL bInitDone=FALSE;
45 #if 0
46 TRACE("0x%x 0x%1x %p\n", hInstDLL, fdwReason, fImpLoad);
47 #endif
48 switch( fdwReason )
50 case DLL_PROCESS_ATTACH:
51 /* Create instance data */
52 if(!bInitDone)
54 /* Initialize global stuff just once */
55 InitializeCriticalSection(&ASPI_CritSection);
56 bInitDone=TRUE;
58 break;
59 case DLL_PROCESS_DETACH:
60 /* Destroy instance data */
61 break;
62 case DLL_THREAD_ATTACH:
63 case DLL_THREAD_DETACH:
64 break;
66 return TRUE;
67 #else /* defined(linux) */
68 return TRUE;
69 #endif /* defined(linux) */
72 #ifdef linux
74 static int
75 ASPI_OpenDevice(SRB_ExecSCSICmd *prb)
77 int fd;
78 char idstr[20];
79 char device_str[50];
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);
93 return curr->fd;
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);
103 return -1;
106 TRACE("Opening device %s=%s\n", idstr, device_str);
108 fd = open(device_str, O_RDWR);
109 if (fd == -1) {
110 int save_error = errno;
111 #ifdef HAVE_STRERROR
112 ERR("Error opening device %s, error '%s'\n", device_str, strerror(save_error));
113 #else
114 ERR("Error opening device %s, error %d\n", device_str, save_error);
115 #endif
116 return -1;
119 /* device is now open */
120 curr = HeapAlloc( GetProcessHeap(), 0, sizeof(ASPI_DEVICE_INFO) );
121 curr->fd = fd;
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);
131 return fd;
135 static void
136 ASPI_DebugPrintCmd(SRB_ExecSCSICmd *prb)
138 BYTE cmd;
139 int i;
140 BYTE *cdb;
142 switch (prb->CDBByte[0]) {
143 case CMD_INQUIRY:
144 TRACE("{\n");
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]);
150 TRACE("}\n");
151 break;
152 case CMD_SCAN_SCAN:
153 TRACE("Transfer Length: %d\n", prb->CDBByte[4]);
154 break;
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");
168 else {
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];
184 if (TRACE_ON(aspi))
186 DPRINTF("CDB buffer[");
187 for (i = 0; i < prb->SRB_CDBLen; i++) {
188 if (i != 0) DPRINTF(",");
189 DPRINTF("%02x", *cdb++);
191 DPRINTF("]\n");
195 static void
196 ASPI_PrintSenseArea(SRB_ExecSCSICmd *prb)
198 int i;
199 BYTE *cdb;
201 if (TRACE_ON(aspi))
203 cdb = &prb->CDBByte[16];
204 DPRINTF("SenseArea[");
205 for (i = 0; i < prb->SRB_SenseLen; i++) {
206 if (i) DPRINTF(",");
207 DPRINTF("%02x", *cdb++);
209 DPRINTF("]\n");
213 static void
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]) {
221 case CMD_INQUIRY:
222 TRACE("Vendor: '%s'\n", prb->SRB_BufPointer + INQUIRY_VENDOR);
223 break;
224 case CMD_TEST_UNIT_READY:
225 ASPI_PrintSenseArea(prb);
226 break;
230 static WORD
231 ASPI_ExecScsiCmd(SRB_ExecSCSICmd *lpPRB)
233 struct sg_header *sg_hd, *sg_reply_hdr;
234 int status;
235 int in_len, out_len;
236 int error_code = 0;
237 int fd;
239 ASPI_DebugPrintCmd(lpPRB);
241 fd = ASPI_OpenDevice(lpPRB);
242 if (fd == -1) {
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;
246 return SS_NO_DEVICE;
249 sg_hd = NULL;
250 sg_reply_hdr = NULL;
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;
257 return 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);
271 else {
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;
285 else {
286 out_len = SCSI_OFF;
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);
297 if (status < 0) {
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");
301 #ifdef HAVE_STRERROR
302 WARN("error:= '%s'\n", strerror(save_error));
303 #else
304 WARN("error:= %d\n", save_error);
305 #endif
307 goto error_exit;
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);
313 goto error_exit;
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);
319 goto error_exit;
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)
330 sense_len = 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);
348 /* now do posting */
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);
355 else
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);
363 return SS_PENDING;
364 /* In real WNASPI32 stuff really is always pending because ASPI does things
365 in the background, but we are not doing that (yet) */
367 error_exit:
368 if (error_code == EBUSY) {
369 lpPRB->SRB_Status = SS_ASPI_IS_BUSY;
370 TRACE("Device busy\n");
372 else {
373 WARN("Failed\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.
394 * RETURNS
395 * HIWORD: 0.
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)
410 #ifdef linux
411 switch (lpSRB->common.SRB_Cmd) {
412 case SC_HA_INQUIRY:
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);
421 return SS_COMP;
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 */
425 SRB tmpsrb;
426 char inqbuf[200];
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);
433 #undef X
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
442 X(Status);
443 #undef 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);
446 break;
448 case SC_EXEC_SCSI_CMD:
449 return ASPI_ExecScsiCmd(&lpSRB->cmd);
450 break;
451 case SC_ABORT_SRB:
452 FIXME("Not implemented SC_ABORT_SRB\n");
453 break;
454 case SC_RESET_DEV:
455 FIXME("Not implemented SC_RESET_DEV\n");
456 break;
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");
461 break;
462 #endif
463 default:
464 WARN("Unknown command %d\n", lpSRB->common.SRB_Cmd);
466 return SS_INVALID_SRB;
467 #else
468 return SS_INVALID_SRB;
469 #endif
473 /***********************************************************************
474 * GetASPI32DLLVersion32 (WNASPI32.3)
477 DWORD WINAPI GetASPI32DLLVersion()
479 #ifdef linux
480 return (DWORD)1;
481 #else
482 return (DWORD)0;
483 #endif