Changed some treeview related definitions.
[wine] / dlls / winaspi / winaspi16.c
1 #include <stdlib.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <ldt.h>
7 #include <memory.h>
8 #include <unistd.h>
9 #include <callback.h>
10 #include <string.h>
11 #include "windows.h"
12 #include "aspi.h"
13 #include "winaspi.h"
14 #include "options.h"
15 #include "heap.h"
16 #include "debug.h"
17 #include "selectors.h"
18 #include "module.h"
19 #include "miscemu.h"
20
21
22 /* FIXME!
23  * 1) Residual byte length reporting not handled
24  * 2) Make this code re-entrant for multithreading
25  * 3) Only linux supported so far
26  */
27
28 #ifdef linux
29 static int
30 ASPI_OpenDevice16(SRB_ExecSCSICmd16 *prb)
31 {
32     int fd;
33     char        idstr[20];
34     char        device_str[50];
35     ASPI_DEVICE_INFO *curr;
36
37     /* search list of devices to see if we've opened it already.
38      * There is not an explicit open/close in ASPI land, so hopefully
39      * keeping a device open won't be a problem.
40      */
41
42     for (curr = ASPI_open_devices; curr; curr = curr->next) {
43         if (curr->hostId == prb->SRB_HaId &&
44             curr->target == prb->SRB_Target &&
45             curr->lun == prb->SRB_Lun) {
46             return curr->fd;
47         }
48     }
49
50     /* device wasn't cached, go ahead and open it */
51     sprintf(idstr, "scsi c%1dt%1dd%1d", prb->SRB_HaId, prb->SRB_Target, prb->SRB_Lun);
52
53     if (!PROFILE_GetWineIniString(idstr, "Device", "", device_str, sizeof(device_str))) {
54         TRACE(aspi, "Trying to open unlisted scsi device %s\n", idstr);
55         return -1;
56     }
57
58     TRACE(aspi, "Opening device %s=%s\n", idstr, device_str);
59
60     fd = open(device_str, O_RDWR);
61     if (fd == -1) {
62         int save_error = errno;
63 #ifdef HAVE_STRERROR
64         ERR(aspi, "Error opening device %s, error '%s'\n", device_str, strerror(save_error));
65 #else
66     ERR(aspi, "Error opening device %s, error %d\n", device_str, save_error);
67 #endif
68         return -1;
69     }
70
71     /* device is now open */
72     curr = HeapAlloc( SystemHeap, 0, sizeof(ASPI_DEVICE_INFO) );
73     curr->fd = fd;
74     curr->hostId = prb->SRB_HaId;
75     curr->target = prb->SRB_Target;
76     curr->lun = prb->SRB_Lun;
77
78     /* insert new record at beginning of open device list */
79     curr->next = ASPI_open_devices;
80     ASPI_open_devices = curr;
81     return fd;
82 }
83
84
85 static void
86 ASPI_DebugPrintCmd(SRB_ExecSCSICmd16 *prb, UINT16 mode)
87 {
88   BYTE  cmd;
89   int   i;
90   BYTE *cdb;
91   BYTE *lpBuf = 0;
92   dbg_decl_str(aspi, 512);
93
94   switch (mode)
95   {
96       case ASPI_DOS:
97         /* translate real mode address */
98         if (prb->SRB_BufPointer)
99             lpBuf = (BYTE *)DOSMEM_MapRealToLinear((UINT32)prb->SRB_BufPointer);
100         break;
101       case ASPI_WIN16:
102         lpBuf = PTR_SEG_TO_LIN(prb->SRB_BufPointer);
103         break;
104   }
105
106   switch (prb->CDBByte[0]) {
107   case CMD_INQUIRY:
108     TRACE(aspi, "{\n");
109     TRACE(aspi, "\tEVPD: %d\n", prb->CDBByte[1] & 1);
110     TRACE(aspi, "\tLUN: %d\n", (prb->CDBByte[1] & 0xc) >> 1);
111     TRACE(aspi, "\tPAGE CODE: %d\n", prb->CDBByte[2]);
112     TRACE(aspi, "\tALLOCATION LENGTH: %d\n", prb->CDBByte[4]);
113     TRACE(aspi, "\tCONTROL: %d\n", prb->CDBByte[5]);
114     TRACE(aspi, "}\n");
115     break;
116   case CMD_SCAN_SCAN:
117     TRACE(aspi, "Transfer Length: %d\n", prb->CDBByte[4]);
118     break;
119   }
120
121   TRACE(aspi, "Host Adapter: %d\n", prb->SRB_HaId);
122   TRACE(aspi, "Flags: %d\n", prb->SRB_Flags);
123   if (TARGET_TO_HOST(prb)) {
124     TRACE(aspi, "\tData transfer: Target to host. Length checked.\n");
125   }
126   else if (HOST_TO_TARGET(prb)) {
127     TRACE(aspi, "\tData transfer: Host to target. Length checked.\n");
128   }
129   else if (NO_DATA_TRANSFERED(prb)) {
130     TRACE(aspi, "\tData transfer: none\n");
131   }
132   else {
133     WARN(aspi, "\tTransfer by scsi cmd. Length not checked\n");
134   }
135
136   TRACE(aspi, "\tResidual byte length reporting %s\n", prb->SRB_Flags & 0x4 ? "enabled" : "disabled");
137   TRACE(aspi, "\tLinking %s\n", prb->SRB_Flags & 0x2 ? "enabled" : "disabled");
138   TRACE(aspi, "\tPosting %s\n", prb->SRB_Flags & 0x1 ? "enabled" : "disabled");
139   TRACE(aspi, "Target: %d\n", prb->SRB_Target);
140   TRACE(aspi, "Lun: %d\n", prb->SRB_Lun);
141   TRACE(aspi, "BufLen: %ld\n", prb->SRB_BufLen);
142   TRACE(aspi, "SenseLen: %d\n", prb->SRB_SenseLen);
143   TRACE(aspi, "BufPtr: %lx (%p)\n", prb->SRB_BufPointer, lpBuf);
144   TRACE(aspi, "LinkPointer %lx\n", prb->SRB_Rsvd1);
145   TRACE(aspi, "CDB Length: %d\n", prb->SRB_CDBLen);
146   TRACE(aspi, "POST Proc: %lx\n", (DWORD) prb->SRB_PostProc);
147   cdb = &prb->CDBByte[0];
148   cmd = prb->CDBByte[0];
149   for (i = 0; i < prb->SRB_CDBLen; i++) {
150     if (i != 0) dsprintf(aspi, ",");
151     dsprintf(aspi, "%02x", *cdb++);
152   }
153   TRACE(aspi, "CDB buffer[%s]\n", dbg_str(aspi));
154 }
155
156 static void
157 ASPI_PrintSenseArea16(SRB_ExecSCSICmd16 *prb)
158 {
159   int   i;
160   BYTE *cdb;
161   dbg_decl_str(aspi, 512);
162
163   cdb = &prb->CDBByte[0];
164   for (i = 0; i < prb->SRB_SenseLen; i++) {
165     if (i) dsprintf(aspi, ",");
166     dsprintf(aspi, "%02x", *cdb++);
167   }
168   TRACE(aspi, "SenseArea[%s]\n", dbg_str(aspi));
169 }
170
171 static void
172 ASPI_DebugPrintResult(SRB_ExecSCSICmd16 *prb, UINT16 mode)
173 {
174   BYTE *lpBuf = 0;
175
176   switch (mode)
177   {
178       case ASPI_DOS:
179         /* translate real mode address */
180         if (prb->SRB_BufPointer)
181             lpBuf = (BYTE *)DOSMEM_MapRealToLinear((UINT32)prb->SRB_BufPointer);
182         break;
183       case ASPI_WIN16:
184         lpBuf = PTR_SEG_TO_LIN(prb->SRB_BufPointer);
185         break;
186   }
187
188   switch (prb->CDBByte[0]) {
189   case CMD_INQUIRY:
190     TRACE(aspi, "Vendor: '%s'\n", lpBuf + INQUIRY_VENDOR);
191     break;
192   case CMD_TEST_UNIT_READY:
193     ASPI_PrintSenseArea16(prb);
194     break;
195   }
196 }
197
198 static WORD
199 ASPI_ExecScsiCmd(DWORD ptrPRB, UINT16 mode)
200 {
201   SRB_ExecSCSICmd16 *lpPRB = 0;
202   struct sg_header *sg_hd, *sg_reply_hdr;
203   int   status;
204   BYTE *lpBuf = 0;
205   int   in_len, out_len;
206   int   error_code = 0;
207   int   fd;
208
209   switch (mode)
210   {
211       case ASPI_DOS:
212         if (ptrPRB)
213             lpPRB = (SRB_ExecSCSICmd16 *)DOSMEM_MapRealToLinear(ptrPRB);
214         break;
215       case ASPI_WIN16:
216         lpPRB = PTR_SEG_TO_LIN(ptrPRB);
217         break;
218   }
219
220   ASPI_DebugPrintCmd(lpPRB, mode);
221
222   fd = ASPI_OpenDevice16(lpPRB);
223   if (fd == -1) {
224       WARN(aspi, "Failed: could not open device. Device permissions !?\n");
225       lpPRB->SRB_Status = SS_ERR;
226       return SS_ERR;
227   }
228
229   sg_hd = NULL;
230   sg_reply_hdr = NULL;
231
232   lpPRB->SRB_Status = SS_PENDING;
233
234   switch (mode)
235   {
236       case ASPI_DOS:
237         /* translate real mode address */
238         if (ptrPRB)
239             lpBuf = (BYTE *)DOSMEM_MapRealToLinear((UINT32)lpPRB->SRB_BufPointer);
240         break;
241       case ASPI_WIN16:
242         lpBuf = PTR_SEG_TO_LIN(lpPRB->SRB_BufPointer);
243         break;
244   }
245
246   if (!lpPRB->SRB_CDBLen) {
247       WARN(aspi, "Failed: lpPRB->SRB_CDBLen = 0.\n");
248       lpPRB->SRB_Status = SS_ERR;
249       return SS_ERR;
250   }
251
252   /* build up sg_header + scsi cmd */
253   if (HOST_TO_TARGET(lpPRB)) {
254     /* send header, command, and then data */
255     in_len = SCSI_OFF + lpPRB->SRB_CDBLen + lpPRB->SRB_BufLen;
256     sg_hd = (struct sg_header *) malloc(in_len);
257     memset(sg_hd, 0, SCSI_OFF);
258     memcpy(sg_hd + 1, &lpPRB->CDBByte[0], lpPRB->SRB_CDBLen);
259     if (lpPRB->SRB_BufLen) {
260       memcpy(((BYTE *) sg_hd) + SCSI_OFF + lpPRB->SRB_CDBLen, lpBuf, lpPRB->SRB_BufLen);
261     }
262   }
263   else {
264     /* send header and command - no data */
265     in_len = SCSI_OFF + lpPRB->SRB_CDBLen;
266     sg_hd = (struct sg_header *) malloc(in_len);
267     memset(sg_hd, 0, SCSI_OFF);
268     memcpy(sg_hd + 1, &lpPRB->CDBByte[0], lpPRB->SRB_CDBLen);
269   }
270
271   if (TARGET_TO_HOST(lpPRB)) {
272     out_len = SCSI_OFF + lpPRB->SRB_BufLen;
273     sg_reply_hdr = (struct sg_header *) malloc(out_len);
274     memset(sg_reply_hdr, 0, SCSI_OFF);
275     sg_hd->reply_len = out_len;
276   }
277   else {
278     out_len = SCSI_OFF;
279     sg_reply_hdr = (struct sg_header *) malloc(out_len);
280     memset(sg_reply_hdr, 0, SCSI_OFF);
281     sg_hd->reply_len = out_len;
282   }
283
284   status = write(fd, sg_hd, in_len);
285   if (status < 0 || status != in_len) {
286       int save_error = errno;
287
288     WARN(aspi, "Not enough bytes written to scsi device bytes=%d .. %d\n", in_len, status);
289     if (status < 0) {
290                 if (save_error == ENOMEM) {
291             MSG("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");
292         }
293 #ifdef HAVE_STRERROR
294                 WARN(aspi, "error:= '%s'\n", strerror(save_error));
295 #else
296                 WARN(aspi, "error:= %d\n", save_error);
297 #endif
298     }
299     goto error_exit;
300   }
301
302   status = read(fd, sg_reply_hdr, out_len);
303   if (status < 0 || status != out_len) {
304     WARN(aspi, "not enough bytes read from scsi device%d\n", status);
305     goto error_exit;
306   }
307
308   if (sg_reply_hdr->result != 0) {
309     error_code = sg_reply_hdr->result;
310     WARN(aspi, "reply header error (%d)\n", sg_reply_hdr->result);
311     goto error_exit;
312   }
313
314   if (TARGET_TO_HOST(lpPRB) && lpPRB->SRB_BufLen) {
315     memcpy(lpBuf, sg_reply_hdr + 1, lpPRB->SRB_BufLen);
316   }
317
318   /* copy in sense buffer to amount that is available in client */
319   if (lpPRB->SRB_SenseLen) {
320     int sense_len = lpPRB->SRB_SenseLen;
321     if (lpPRB->SRB_SenseLen > 16)
322       sense_len = 16;
323     memcpy(SENSE_BUFFER(lpPRB), &sg_reply_hdr->sense_buffer[0], sense_len);
324   }
325
326
327   lpPRB->SRB_Status = SS_COMP;
328   lpPRB->SRB_HaStat = HASTAT_OK;
329   lpPRB->SRB_TargStat = STATUS_GOOD;
330
331   /* now do posting */
332
333   if (ASPI_POSTING(lpPRB) && lpPRB->SRB_PostProc) {
334     TRACE(aspi, "Post Routine (%lx) called\n", (DWORD) lpPRB->SRB_PostProc);
335     switch (mode)
336     {
337       case ASPI_DOS:
338       {
339         SEGPTR spPRB = MapLS(lpPRB);
340
341         Callbacks->CallASPIPostProc(lpPRB->SRB_PostProc, spPRB);        
342         UnMapLS(spPRB);
343         break;
344       }
345       case ASPI_WIN16:
346         Callbacks->CallASPIPostProc(lpPRB->SRB_PostProc, ptrPRB);
347         break;
348     }
349   }
350
351   free(sg_reply_hdr);
352   free(sg_hd);
353   ASPI_DebugPrintResult(lpPRB, mode);
354   return SS_COMP;
355   
356 error_exit:
357   if (error_code == EBUSY) {
358       lpPRB->SRB_Status = SS_ASPI_IS_BUSY;
359       TRACE(aspi, "Device busy\n");
360   }
361   else {
362       WARN(aspi, "Failed\n");
363       lpPRB->SRB_Status = SS_ERR;
364   }
365
366   /* I'm not sure exactly error codes work here
367    * We probably should set lpPRB->SRB_TargStat, SRB_HaStat ?
368    */
369   WARN(aspi, "error_exit\n");
370   free(sg_reply_hdr);
371   free(sg_hd);
372   return lpPRB->SRB_Status;
373 }
374 #endif
375
376
377 /***********************************************************************
378  *             GetASPISupportInfo16   (WINASPI.1)
379  */
380
381 WORD WINAPI GetASPISupportInfo16()
382 {
383 #ifdef linux
384     TRACE(aspi, "GETASPISupportInfo16\n");
385     /* high byte SS_COMP - low byte number of host adapters.
386      * FIXME!!! The number of host adapters is incorrect.
387      * I'm not sure how to determine this under linux etc.
388      */
389     return ((SS_COMP << 8) | 1);
390 #else
391     return ((SS_COMP << 8) | 0);
392 #endif
393 }
394
395
396 DWORD ASPI_SendASPICommand(DWORD ptrSRB, UINT16 mode)
397 {
398 #ifdef linux
399   LPSRB16 lpSRB = 0;
400
401   switch (mode)
402   {
403       case ASPI_DOS:
404         if (ptrSRB)
405             lpSRB = (LPSRB16)DOSMEM_MapRealToLinear(ptrSRB);
406         break;
407       case ASPI_WIN16:
408         lpSRB = PTR_SEG_TO_LIN(ptrSRB);
409         break;
410   }
411
412   switch (lpSRB->common.SRB_Cmd) {
413   case SC_HA_INQUIRY:
414     lpSRB->inquiry.SRB_Status = SS_COMP;       /* completed successfully */
415     if (lpSRB->inquiry.SRB_55AASignature == 0x55aa) {
416         TRACE(aspi, "Extended request detected (Adaptec's ASPIxDOS).\nWe don't support it at the moment.\n");
417     }
418     lpSRB->inquiry.SRB_ExtBufferSize = 0x2000; /* bogus value */
419     lpSRB->inquiry.HA_Count = 1;               /* not always */
420     lpSRB->inquiry.HA_SCSI_ID = 7;             /* not always ID 7 */
421     strcat(lpSRB->inquiry.HA_ManagerId, "Wine ASPI16"); /* max 15 chars */
422     strcat(lpSRB->inquiry.HA_Identifier, "Wine host"); /* FIXME: return host
423 adapter name */
424     memset(lpSRB->inquiry.HA_Unique, 0, 16); /* default HA_Unique content */
425     lpSRB->inquiry.HA_Unique[6] = 0x02; /* Maximum Transfer Length (128K, Byte> 4-7) */
426     FIXME(aspi, "ASPI: Partially implemented SC_HA_INQUIRY for adapter %d.\n", lpSRB->inquiry.SRB_HaId);
427     return SS_COMP;
428   case SC_GET_DEV_TYPE:
429     FIXME(aspi, "Not implemented SC_GET_DEV_TYPE\n");
430     break;
431   case SC_EXEC_SCSI_CMD:
432     return ASPI_ExecScsiCmd((DWORD)ptrSRB, mode);
433     break;
434   case SC_RESET_DEV:
435     FIXME(aspi, "Not implemented SC_RESET_DEV\n");
436     break;
437   default:
438     WARN(aspi, "Unknown command %d\n", lpSRB->common.SRB_Cmd);
439   }
440   return SS_INVALID_SRB;
441 #else
442   return SS_INVALID_SRB;
443 #endif
444 }
445
446
447 /***********************************************************************
448  *             SendASPICommand16   (WINASPI.2)
449  */
450 WORD WINAPI SendASPICommand16(SEGPTR segptr_srb)
451 {
452 #ifdef linux
453     return ASPI_SendASPICommand(segptr_srb, ASPI_WIN16);
454 #else
455     return 0; 
456 #endif
457 }
458
459
460 /***********************************************************************
461  *             GetASPIDLLVersion16   (WINASPI.4)
462  */
463
464 DWORD WINAPI GetASPIDLLVersion16()
465 {
466 #ifdef linux
467         return (DWORD)2;
468 #else
469         return (DWORD)0;
470 #endif
471 }
472
473
474 void WINAPI ASPI_DOS_func(CONTEXT *context)
475 {
476         WORD *stack = CTX_SEG_OFF_TO_LIN(context, SS_reg(context), ESP_reg(context));
477         DWORD ptrSRB = *(DWORD *)&stack[2];
478
479         ASPI_SendASPICommand(ptrSRB, ASPI_DOS);
480
481         /* simulate a normal RETF sequence as required by DPMI CallRMProcFar */
482         IP_reg(context) = *(stack++);
483         CS_reg(context) = *(stack++);
484         SP_reg(context) += 2*sizeof(WORD);
485 }
486
487
488 /* returns the address of a real mode callback to ASPI_DOS_func() */
489 void ASPI_DOS_HandleInt(CONTEXT *context)
490 {
491 #ifdef linux
492         FARPROC16 *p = (FARPROC16 *)CTX_SEG_OFF_TO_LIN(context, DS_reg(context), EDX_reg(context));
493         if ((CX_reg(context) == 4) || (CX_reg(context) == 5))
494         {
495         *p = DPMI_AllocInternalRMCB(ASPI_DOS_func);
496         TRACE(aspi, "allocated real mode proc %p\n", *p);
497             AX_reg(context) = CX_reg(context);
498         }
499         else
500         SET_CFLAG(context);
501 #else
502        SET_CFLAG(context);
503 #endif
504 }