blob: 84299f9b81ee38e67e547c1258e0a8fbf2f0dc8f [file] [log] [blame]
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00001/*
2 * Copyright 2000 David Elliott
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000017 */
18
David Elliottc3bcd6c2000-03-08 19:41:49 +000019#include "config.h"
20
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000021#include <stdarg.h>
James Juranf4d5fef2001-01-26 20:43:40 +000022#include <string.h>
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000023#include "windef.h"
David Elliottc3bcd6c2000-03-08 19:41:49 +000024#include "winbase.h"
Alexandre Julliard83f52d12000-09-26 22:20:14 +000025#include "wine/windef16.h"
26#include "wine/winaspi.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000027#include "wine/debug.h"
Jukka Heinonen02e17772002-11-18 22:53:38 +000028#include "dosexe.h"
David Elliottc3bcd6c2000-03-08 19:41:49 +000029#include "winerror.h"
30
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000031WINE_DEFAULT_DEBUG_CHANNEL(aspi);
David Elliottc3bcd6c2000-03-08 19:41:49 +000032
33static HINSTANCE hWNASPI32 = INVALID_HANDLE_VALUE;
34static DWORD (__cdecl *pSendASPI32Command) (LPSRB) = NULL;
35
36static void
37DOSASPI_PostProc( SRB_ExecSCSICmd *lpPRB )
38{
39 DWORD ptrSRB;
40 LPSRB16 lpSRB16;
41
42
Alexandre Julliardab170a92000-09-27 00:25:24 +000043 memcpy(&ptrSRB,lpPRB->SenseArea + lpPRB->SRB_SenseLen,sizeof(DWORD));
Michael Stefaniucdb4eaf52006-10-03 14:04:49 +020044 TRACE("Copying data back to DOS client at 0x%8x\n",ptrSRB);
Alexandre Julliard0d875e72002-08-30 00:03:25 +000045 lpSRB16 = PTR_REAL_TO_LIN(SELECTOROF(ptrSRB),OFFSETOF(ptrSRB));
David Elliottc3bcd6c2000-03-08 19:41:49 +000046 lpSRB16->cmd.SRB_TargStat = lpPRB->SRB_TargStat;
47 lpSRB16->cmd.SRB_HaStat = lpPRB->SRB_HaStat;
Alexandre Julliardab170a92000-09-27 00:25:24 +000048 memcpy(lpSRB16->cmd.CDBByte + lpSRB16->cmd.SRB_CDBLen,lpPRB->SenseArea,lpSRB16->cmd.SRB_SenseLen);
David Elliottc3bcd6c2000-03-08 19:41:49 +000049
50 /* Now do posting */
51 if( lpPRB->SRB_Status == SS_SECURITY_VIOLATION )
52 {
53 /* SS_SECURITY_VIOLATION isn't defined in DOS ASPI */
54 TRACE("Returning SS_NO_DEVICE for SS_SECURITY_VIOLATION\n");
55 lpPRB->SRB_Status = SS_NO_DEVICE;
56 }
57
58 lpSRB16->cmd.SRB_Status = lpPRB->SRB_Status;
59 TRACE("SRB_Status = 0x%x\n", lpPRB->SRB_Status);
60
61 HeapFree(GetProcessHeap(),0,lpPRB);
62
63 if( (lpSRB16->cmd.SRB_Flags & SRB_POSTING) && lpSRB16->cmd.SRB_PostProc )
64 {
65 CONTEXT86 ctx;
66/* The stack should look like this on entry to proc
67 * NOTE: the SDK draws the following diagram bass akwards, use this one
68 * to avoid being confused. Remember, the act of pushing something on
69 * an intel stack involves decreasing the stack pointer by the size of
70 * the data, and then copying the data at the new SP.
71 */
72/***************************
73 * ... Other crap that is already on the stack ...
74 * Segment of SRB Pointer <- SP+6
75 * Offset of SRB Pointer <- SP+4
76 * Segment of return address <- SP+2
77 * Offset of return address <- SP+0
Vincent Béron9a624912002-05-31 23:06:46 +000078 */
David Elliottc3bcd6c2000-03-08 19:41:49 +000079 /* FIXME: I am about 99% sure what is here is correct,
80 * but this code has never been tested (and probably
81 * won't be either until someone finds a DOS program
82 * that actually uses a Post Routine) */
83
84 /* Zero everything */
85 memset(&ctx, 0, sizeof(ctx));
Jukka Heinonenbe3b2562003-08-25 01:01:01 +000086 ctx.EFlags |= V86_FLAG;
87
David Elliottc3bcd6c2000-03-08 19:41:49 +000088 /* CS:IP is routine to call */
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +000089 ctx.SegCs = SELECTOROF(lpSRB16->cmd.SRB_PostProc);
90 ctx.Eip = OFFSETOF(lpSRB16->cmd.SRB_PostProc);
David Elliottc3bcd6c2000-03-08 19:41:49 +000091 /* DPMI_CallRMProc will push the pointer to the stack
92 * it is given (in this case &ptrSRB) with length
Francois Gougetc4b11952007-10-23 15:30:30 +020093 * 2*sizeof(WORD), that is, it copies the contents
David Elliottc3bcd6c2000-03-08 19:41:49 +000094 * of ptrSRB onto the stack, and decs sp by 2*sizeof(WORD).
95 * After doing that, it pushes the return address
96 * onto the stack (so we don't need to worry about that)
97 * So the stack should be okay for the PostProc
98 */
99 if(DPMI_CallRMProc(&ctx, (LPWORD)&ptrSRB, 2, FALSE))
100 {
101 TRACE("DPMI_CallRMProc returned nonzero (error) status\n");
102 }
103 } /* if ((SRB_Flags&SRB_POSTING) && SRB_PostProc) */
104}
105
Vincent Béron9a624912002-05-31 23:06:46 +0000106static
David Elliottc3bcd6c2000-03-08 19:41:49 +0000107DWORD ASPI_SendASPIDOSCommand(DWORD ptrSRB)
108{
109 PSRB_ExecSCSICmd lpPRB;
110 DWORD retval;
111 union tagSRB16 * lpSRB16;
112
Alexandre Julliard0d875e72002-08-30 00:03:25 +0000113 lpSRB16 = PTR_REAL_TO_LIN(SELECTOROF(ptrSRB),OFFSETOF(ptrSRB));
David Elliottc3bcd6c2000-03-08 19:41:49 +0000114
115 retval = SS_ERR;
116 switch( lpSRB16->common.SRB_Cmd )
117 {
118 case SC_HA_INQUIRY:
119 TRACE("SC_HA_INQUIRY\n");
120 /* Format is identical in this case */
121 retval = (*pSendASPI32Command)((LPSRB)lpSRB16);
122 break;
123 case SC_GET_DEV_TYPE:
124 TRACE("SC_GET_DEV_TYPE\n");
125 /* Format is identical in this case */
126 retval = (*pSendASPI32Command)((LPSRB)lpSRB16);
127 break;
128 case SC_EXEC_SCSI_CMD:
129 TRACE("SC_EXEC_SCSI_CMD\n");
Michael Stefaniucdb4eaf52006-10-03 14:04:49 +0200130 TRACE("Copying data from DOS client at 0x%8x\n",ptrSRB);
David Elliottc3bcd6c2000-03-08 19:41:49 +0000131 lpPRB = HeapAlloc(GetProcessHeap(),0,sizeof(SRB)+lpSRB16->cmd.SRB_SenseLen+sizeof(DWORD));
132#define srb_dos_to_w32(name) \
133 lpPRB->SRB_##name = lpSRB16->cmd.SRB_##name
134
135 srb_dos_to_w32(Cmd);
136 srb_dos_to_w32(Status);
137 srb_dos_to_w32(HaId);
138 srb_dos_to_w32(BufLen);
139 srb_dos_to_w32(SenseLen);
140 srb_dos_to_w32(CDBLen);
141 srb_dos_to_w32(Target);
142 srb_dos_to_w32(Lun);
143#undef srb_dos_to_w32
144
145 /* Allow certain flags to go on to WNASPI32, we also need
146 * to make sure SRB_POSTING is enabled */
147 lpPRB->SRB_Flags = SRB_POSTING | (lpSRB16->cmd.SRB_Flags&(SRB_DIR_IN|SRB_DIR_OUT|SRB_ENABLE_RESIDUAL_COUNT));
148
149 /* Pointer to data buffer */
Alexandre Julliard0d875e72002-08-30 00:03:25 +0000150 lpPRB->SRB_BufPointer = PTR_REAL_TO_LIN(SELECTOROF(lpSRB16->cmd.SRB_BufPointer),
151 OFFSETOF(lpSRB16->cmd.SRB_BufPointer));
David Elliottc3bcd6c2000-03-08 19:41:49 +0000152 /* Copy CDB in */
153 memcpy(&lpPRB->CDBByte[0],&lpSRB16->cmd.CDBByte[0],lpSRB16->cmd.SRB_CDBLen);
154
155 /* Set post proc to our post proc */
Andrew Talbot7e917a02008-07-06 13:00:58 +0100156 lpPRB->SRB_PostProc = DOSASPI_PostProc;
David Elliottc3bcd6c2000-03-08 19:41:49 +0000157
158 /* Stick the DWORD after all the sense info */
Alexandre Julliardab170a92000-09-27 00:25:24 +0000159 memcpy(lpPRB->SenseArea + lpPRB->SRB_SenseLen,&ptrSRB,sizeof(DWORD));
David Elliottc3bcd6c2000-03-08 19:41:49 +0000160 retval = (*pSendASPI32Command)((LPSRB)lpPRB);
161 break;
162 case SC_ABORT_SRB:
163 TRACE("SC_ABORT_SRB\n");
164 /* Would need some sort of table of active shit */
165 break;
166 case SC_RESET_DEV:
167 TRACE("SC_RESET_DEV\n");
168 break;
169 default:
Francois Gouget6d442ae2005-11-23 20:14:43 +0100170 TRACE("Unknown command code\n");
David Elliottc3bcd6c2000-03-08 19:41:49 +0000171 break;
172 }
173
Michael Stefaniucdb4eaf52006-10-03 14:04:49 +0200174 TRACE("Returning %x\n", retval );
David Elliottc3bcd6c2000-03-08 19:41:49 +0000175 return retval;
176}
177
Andrew Talbotbf98c9d2007-02-02 14:38:45 +0000178static void WINAPI ASPI_DOS_func(CONTEXT86 *context)
David Elliottc3bcd6c2000-03-08 19:41:49 +0000179{
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000180 WORD *stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp);
David Elliottc3bcd6c2000-03-08 19:41:49 +0000181 DWORD ptrSRB = *(DWORD *)&stack[2];
182
183 ASPI_SendASPIDOSCommand(ptrSRB);
184
185 /* simulate a normal RETF sequence as required by DPMI CallRMProcFar */
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000186 context->Eip = *(stack++);
187 context->SegCs = *(stack++);
188 context->Esp += 2*sizeof(WORD);
David Elliottc3bcd6c2000-03-08 19:41:49 +0000189}
190
191
Alexandre Julliard8cd55d02001-12-04 19:54:44 +0000192/**********************************************************************
Alexandre Julliard58cd87a2010-01-04 13:44:22 +0100193 * ASPIHandler
Alexandre Julliard8cd55d02001-12-04 19:54:44 +0000194 *
195 * returns the address of a real mode callback to ASPI_DOS_func()
196 */
Alexandre Julliard58cd87a2010-01-04 13:44:22 +0100197void DOSVM_ASPIHandler( CONTEXT86 *context )
David Elliottc3bcd6c2000-03-08 19:41:49 +0000198{
Michael Stefaniucc6be3fe2009-03-04 10:41:06 +0100199 FARPROC16 *p = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
David Elliottc3bcd6c2000-03-08 19:41:49 +0000200 TRACE("DOS ASPI opening\n");
201 if ((CX_reg(context) == 4) || (CX_reg(context) == 5))
202 {
203 if( hWNASPI32 == INVALID_HANDLE_VALUE )
204 {
205 TRACE("Loading WNASPI32\n");
Eric Pouech12222f02000-04-29 14:29:41 +0000206 hWNASPI32 = LoadLibraryExA("WNASPI32", 0, 0);
David Elliottc3bcd6c2000-03-08 19:41:49 +0000207 }
208
209 if( hWNASPI32 == INVALID_HANDLE_VALUE )
210 {
211 ERR("Error loading WNASPI32\n");
212 goto error_exit;
213 }
214
215 /* Get SendASPI32Command by Ordinal 2 */
216 /* Cast to correct argument/return types */
Mike McCormack93ab6952005-08-26 08:53:31 +0000217 pSendASPI32Command = (DWORD (*)(LPSRB))GetProcAddress(hWNASPI32, (LPCSTR)2);
David Elliottc3bcd6c2000-03-08 19:41:49 +0000218 if( !pSendASPI32Command )
219 {
220 ERR("Error getting ordinal 2 from WNASPI32\n");
221 goto error_exit;
222 }
223
224 *p = DPMI_AllocInternalRMCB(ASPI_DOS_func);
225 TRACE("allocated real mode proc %p\n", *p);
Alexandre Julliard3fa613c2002-08-31 18:47:00 +0000226 SET_AX( context, CX_reg(context) );
David Elliottc3bcd6c2000-03-08 19:41:49 +0000227
228 return;
229 }
230error_exit:
231 /* Return some error... General Failure sounds okay */
Alexandre Julliard3fa613c2002-08-31 18:47:00 +0000232 SET_AX( context, ERROR_GEN_FAILURE );
David Elliottc3bcd6c2000-03-08 19:41:49 +0000233 SET_CFLAG(context);
234}