winaspi32.c 18.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright 1997 Bruce Milner
 * Copyright 1998 Andreas Mohr
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 19
 */

20 21
#include "config.h"

22
#include <assert.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
23
#include <stdlib.h>
24
#include <stdarg.h>
25
#include <stdio.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
26 27 28
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
29
#include <string.h>
30 31 32
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
33

34
#include "windef.h"
35
#include "winbase.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
36 37
#include "aspi.h"
#include "wnaspi32.h"
38
#include "winescsi.h"
39
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
40

41
WINE_DEFAULT_DEBUG_CHANNEL(aspi);
42

Alexandre Julliard's avatar
Alexandre Julliard committed
43 44 45
/* FIXME!
 * 1) Residual byte length reporting not handled
 * 2) Make this code re-entrant for multithreading
46
 *    -- Added CriticalSection to OpenDevices function
Alexandre Julliard's avatar
Alexandre Julliard committed
47
 * 3) Only linux supported so far
48 49 50
 * 4) Leaves sg devices open. This may or may not be okay.  A better solution
 *    would be to close the file descriptors when the thread/process using
 *    them no longer needs them.
Alexandre Julliard's avatar
Alexandre Julliard committed
51 52 53
 */

#ifdef linux
Patrik Stridvall's avatar
Patrik Stridvall committed
54 55

static ASPI_DEVICE_INFO *ASPI_open_devices = NULL;
56 57 58 59 60 61

static CRITICAL_SECTION ASPI_CritSection;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
    0, 0, &ASPI_CritSection,
    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
62
      0, 0, { (DWORD_PTR)(__FILE__ ": ASPI_CritSection") }
63 64
};
static CRITICAL_SECTION ASPI_CritSection = { &critsect_debug, -1, 0, 0, 0, 0 };
65

66 67 68
#endif /* defined(linux) */


69
BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
70
{
71
#ifdef linux
72 73 74
	switch( fdwReason )
	{
	case DLL_PROCESS_ATTACH:
75
            DisableThreadLibraryCalls(hInstDLL);
76 77
            SCSI_Init();
            break;
78
	case DLL_PROCESS_DETACH:
79 80
            DeleteCriticalSection( &ASPI_CritSection );
            break;
81
	}
82
#endif /* defined(linux) */
83
	return TRUE;
84
}
Patrik Stridvall's avatar
Patrik Stridvall committed
85

86

87 88
#ifdef linux

Alexandre Julliard's avatar
Alexandre Julliard committed
89
static int
90
ASPI_OpenDevice(SRB_ExecSCSICmd *prb)
Alexandre Julliard's avatar
Alexandre Julliard committed
91 92
{
    int	fd;
93
    DWORD	hc;
Alexandre Julliard's avatar
Alexandre Julliard committed
94 95 96 97 98 99 100
    ASPI_DEVICE_INFO *curr;

    /* search list of devices to see if we've opened it already.
     * There is not an explicit open/close in ASPI land, so hopefully
     * keeping a device open won't be a problem.
     */

101
    EnterCriticalSection(&ASPI_CritSection);
Alexandre Julliard's avatar
Alexandre Julliard committed
102 103 104 105
    for (curr = ASPI_open_devices; curr; curr = curr->next) {
	if (curr->hostId == prb->SRB_HaId &&
	    curr->target == prb->SRB_Target &&
	    curr->lun == prb->SRB_Lun) {
106
            LeaveCriticalSection(&ASPI_CritSection);
Alexandre Julliard's avatar
Alexandre Julliard committed
107 108 109
	    return curr->fd;
	}
    }
110
    LeaveCriticalSection(&ASPI_CritSection);
Alexandre Julliard's avatar
Alexandre Julliard committed
111

112
    if (prb->SRB_HaId >= ASPI_GetNumControllers())
113 114
	return -1;

115 116
    hc = ASPI_GetHCforController( prb->SRB_HaId );
    fd = SCSI_OpenDevice( HIWORD(hc), LOWORD(hc), prb->SRB_Target, prb->SRB_Lun);
Alexandre Julliard's avatar
Alexandre Julliard committed
117

118
    if (fd == -1)
Alexandre Julliard's avatar
Alexandre Julliard committed
119 120 121
	return -1;

    /* device is now open */
122 123
    /* FIXME: Let users specify SCSI timeout in registry */
    SCSI_LinuxSetTimeout( fd, SCSI_DEFAULT_TIMEOUT );
124

125
    curr = HeapAlloc( GetProcessHeap(), 0, sizeof(ASPI_DEVICE_INFO) );
Alexandre Julliard's avatar
Alexandre Julliard committed
126 127 128 129 130 131
    curr->fd = fd;
    curr->hostId = prb->SRB_HaId;
    curr->target = prb->SRB_Target;
    curr->lun = prb->SRB_Lun;

    /* insert new record at beginning of open device list */
132
    EnterCriticalSection(&ASPI_CritSection);
Alexandre Julliard's avatar
Alexandre Julliard committed
133 134
    curr->next = ASPI_open_devices;
    ASPI_open_devices = curr;
135
    LeaveCriticalSection(&ASPI_CritSection);
Alexandre Julliard's avatar
Alexandre Julliard committed
136 137 138 139 140
    return fd;
}


static void
141
ASPI_DebugPrintCmd(SRB_ExecSCSICmd *prb)
Alexandre Julliard's avatar
Alexandre Julliard committed
142 143 144 145 146 147
{
  int	i;
  BYTE *cdb;

  switch (prb->CDBByte[0]) {
  case CMD_INQUIRY:
148
    TRACE("INQUIRY {\n");
149 150 151 152 153 154
    TRACE("\tEVPD: %d\n", prb->CDBByte[1] & 1);
    TRACE("\tLUN: %d\n", (prb->CDBByte[1] & 0xc) >> 1);
    TRACE("\tPAGE CODE: %d\n", prb->CDBByte[2]);
    TRACE("\tALLOCATION LENGTH: %d\n", prb->CDBByte[4]);
    TRACE("\tCONTROL: %d\n", prb->CDBByte[5]);
    TRACE("}\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
155 156
    break;
  case CMD_SCAN_SCAN:
157
    TRACE("Transfer Length: %d\n", prb->CDBByte[4]);
Alexandre Julliard's avatar
Alexandre Julliard committed
158 159 160
    break;
  }

161 162
  TRACE("Host Adapter: %d\n", prb->SRB_HaId);
  TRACE("Flags: %d\n", prb->SRB_Flags);
Alexandre Julliard's avatar
Alexandre Julliard committed
163
  if (TARGET_TO_HOST(prb)) {
164
    TRACE("\tData transfer: Target to host. Length checked.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
165 166
  }
  else if (HOST_TO_TARGET(prb)) {
167
    TRACE("\tData transfer: Host to target. Length checked.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
168
  }
169
  else if (NO_DATA_TRANSFERRED(prb)) {
170
    TRACE("\tData transfer: none\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
171 172
  }
  else {
173
    WARN("\tTransfer by scsi cmd. Length not checked.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
174 175
  }

176 177 178 179 180
  TRACE("\tResidual byte length reporting %s\n", prb->SRB_Flags & 0x4 ? "enabled" : "disabled");
  TRACE("\tLinking %s\n", prb->SRB_Flags & 0x2 ? "enabled" : "disabled");
  TRACE("\tPosting %s\n", prb->SRB_Flags & 0x1 ? "enabled" : "disabled");
  TRACE("Target: %d\n", prb->SRB_Target);
  TRACE("Lun: %d\n", prb->SRB_Lun);
181
  TRACE("BufLen: %d\n", prb->SRB_BufLen);
182 183 184
  TRACE("SenseLen: %d\n", prb->SRB_SenseLen);
  TRACE("BufPtr: %p\n", prb->SRB_BufPointer);
  TRACE("CDB Length: %d\n", prb->SRB_CDBLen);
185
  TRACE("POST Proc: %p\n", prb->SRB_PostProc);
Alexandre Julliard's avatar
Alexandre Julliard committed
186
  cdb = &prb->CDBByte[0];
187
  if (TRACE_ON(aspi)) {
188
      TRACE("CDB buffer[");
189
      for (i = 0; i < prb->SRB_CDBLen; i++) {
190 191
          if (i != 0) TRACE(",");
          TRACE("%02x", *cdb++);
192
      }
193
      TRACE("]\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
194 195 196
  }
}

Andreas Mohr's avatar
Andreas Mohr committed
197 198 199 200 201 202
static void
ASPI_PrintCDBArea(SRB_ExecSCSICmd *prb)
{
    if (TRACE_ON(aspi))
    {
	int i;
203
        TRACE("CDB[");
Andreas Mohr's avatar
Andreas Mohr committed
204
        for (i = 0; i < prb->SRB_CDBLen; i++) {
205 206
            if (i) TRACE(",");
            TRACE("%02x", prb->CDBByte[i]);
Andreas Mohr's avatar
Andreas Mohr committed
207
        }
208
        TRACE("]\n");
Andreas Mohr's avatar
Andreas Mohr committed
209 210 211
    }
}

Alexandre Julliard's avatar
Alexandre Julliard committed
212
static void
213
ASPI_PrintSenseArea(SRB_ExecSCSICmd *prb)
Alexandre Julliard's avatar
Alexandre Julliard committed
214 215
{
  int	i;
216
  BYTE	*rqbuf = prb->SenseArea;
Alexandre Julliard's avatar
Alexandre Julliard committed
217

218 219
  if (TRACE_ON(aspi))
  {
220
      TRACE("Request Sense reports:\n");
221
      if ((rqbuf[0]&0x7f)!=0x70) {
222
	      TRACE("\tInvalid sense header: 0x%02x instead of 0x70\n", rqbuf[0]&0x7f);
223 224
	      return;
      }
225 226 227 228
      TRACE("\tCurrent command read filemark: %s\n",(rqbuf[2]&0x80)?"yes":"no");
      TRACE("\tEarly warning passed: %s\n",(rqbuf[2]&0x40)?"yes":"no");
      TRACE("\tIncorrect blocklength: %s\n",(rqbuf[2]&0x20)?"yes":"no");
      TRACE("\tSense Key: %d\n",rqbuf[2]&0xf);
229
      if (rqbuf[0]&0x80)
230 231 232 233
	TRACE("\tResidual Length: %d\n",rqbuf[3]*0x1000000+rqbuf[4]*0x10000+rqbuf[5]*0x100+rqbuf[6]);
      TRACE("\tAdditional Sense Length: %d\n",rqbuf[7]);
      TRACE("\tAdditional Sense Code: %d\n",rqbuf[12]);
      TRACE("\tAdditional Sense Code Qualifier: %d\n",rqbuf[13]);
234
      if (rqbuf[15]&0x80) {
235
	TRACE("\tIllegal Param is in %s\n",(rqbuf[15]&0x40)?"the CDB":"the Data Out Phase");
236
	if (rqbuf[15]&0x8) {
237
	  TRACE("Pointer at %d, bit %d\n",rqbuf[16]*256+rqbuf[17],rqbuf[15]&0x7);
238 239
	}
      }
240
      TRACE("SenseArea[");
241
      for (i = 0; i < prb->SRB_SenseLen; i++) {
242 243
	if (i) TRACE(",");
	TRACE("%02x", *rqbuf++);
244
      }
245
      TRACE("]\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
246 247 248 249
  }
}

static void
250
ASPI_DebugPrintResult(SRB_ExecSCSICmd *prb)
Alexandre Julliard's avatar
Alexandre Julliard committed
251 252
{

253 254 255
  TRACE("SRB_Status: %x\n", prb->SRB_Status);
  TRACE("SRB_HaStat: %x\n", prb->SRB_HaStat);
  TRACE("SRB_TargStat: %x\n", prb->SRB_TargStat);
Alexandre Julliard's avatar
Alexandre Julliard committed
256 257
  switch (prb->CDBByte[0]) {
  case CMD_INQUIRY:
258
    TRACE("Vendor: '%s'\n", prb->SRB_BufPointer + INQUIRY_VENDOR);
Alexandre Julliard's avatar
Alexandre Julliard committed
259 260
    break;
  case CMD_TEST_UNIT_READY:
261
    ASPI_PrintSenseArea(prb);
Alexandre Julliard's avatar
Alexandre Julliard committed
262 263 264 265
    break;
  }
}

266 267 268 269 270 271 272
/* Posting must be done in such a way that as soon as the SRB_Status is set
 * we don't touch the SRB anymore because it could possibly be freed
 * if the app is doing ASPI polling
 */
static DWORD
WNASPI32_DoPosting( SRB_ExecSCSICmd *lpPRB, DWORD status )
{
273
	void (*SRB_PostProc)(SRB_ExecSCSICmd *) = lpPRB->SRB_PostProc;
274 275 276 277 278 279 280 281 282 283 284 285 286
	BYTE SRB_Flags = lpPRB->SRB_Flags;
	if( status == SS_PENDING )
	{
		WARN("Tried posting SS_PENDING\n");
		return SS_PENDING;
	}
	lpPRB->SRB_Status = status;
	/* lpPRB is NOT safe, it could be freed in another thread */

	if (SRB_PostProc)
	{
		if (SRB_Flags & 0x1)
		{
287
			TRACE("Post Routine (%p) called\n", SRB_PostProc);
288 289 290 291 292 293 294
			/* Even though lpPRB could have been freed by
			 * the program.. that's unlikely if it planned
			 * to use it in the PostProc
			 */
			(*SRB_PostProc)(lpPRB);
		}
		else if (SRB_Flags & SRB_EVENT_NOTIFY) {
295 296
			TRACE("Setting event %p\n", SRB_PostProc);
			SetEvent(SRB_PostProc);
297 298 299 300 301
		}
	}
	return SS_PENDING;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
302
static WORD
303
ASPI_ExecScsiCmd(SRB_ExecSCSICmd *lpPRB)
Alexandre Julliard's avatar
Alexandre Julliard committed
304 305
{
  struct sg_header *sg_hd, *sg_reply_hdr;
306
  WORD ret;
307
  DWORD	status;
Alexandre Julliard's avatar
Alexandre Julliard committed
308
  int	in_len, out_len;
309
  int   num_controllers = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
310 311
  int	error_code = 0;
  int	fd;
312
  DWORD SRB_Status;
Alexandre Julliard's avatar
Alexandre Julliard committed
313

314
  num_controllers = ASPI_GetNumControllers();
315 316
  if (lpPRB->SRB_HaId >= num_controllers) {
      WARN("Failed: Wanted hostadapter with index %d, but we have only %d.\n",
317 318 319 320 321 322 323 324 325
	  lpPRB->SRB_HaId, num_controllers
      );
      return WNASPI32_DoPosting( lpPRB, SS_INVALID_HA );
  }
  fd = ASPI_OpenDevice(lpPRB);
  if (fd == -1) {
      return WNASPI32_DoPosting( lpPRB, SS_NO_DEVICE );
  }
    
326 327 328 329
  /* FIXME: hackmode */
#define MAKE_TARGET_TO_HOST(lpPRB) \
  	if (!TARGET_TO_HOST(lpPRB)) { \
	    WARN("program was not sending target_to_host for cmd %x (flags=%x),correcting.\n",lpPRB->CDBByte[0],lpPRB->SRB_Flags); \
330
	    lpPRB->SRB_Flags |= 0x08; \
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
	}
#define MAKE_HOST_TO_TARGET(lpPRB) \
  	if (!HOST_TO_TARGET(lpPRB)) { \
	    WARN("program was not sending host_to_target for cmd %x (flags=%x),correcting.\n",lpPRB->CDBByte[0],lpPRB->SRB_Flags); \
	    lpPRB->SRB_Flags |= 0x10; \
	}
  switch (lpPRB->CDBByte[0]) {
  case 0x12: /* INQUIRY */
  case 0x5a: /* MODE_SENSE_10 */
  case 0xa4: /* REPORT_KEY (DVD) MMC-2 */
  case 0xad: /* READ DVD STRUCTURE MMC-2 */
        MAKE_TARGET_TO_HOST(lpPRB)
	break;
  case 0xa3: /* SEND KEY (DVD) MMC-2 */
        MAKE_HOST_TO_TARGET(lpPRB)
	break;
  default:
	if ((((lpPRB->SRB_Flags & 0x18) == 0x00) ||
	     ((lpPRB->SRB_Flags & 0x18) == 0x18)
	    ) && lpPRB->SRB_BufLen
	) {
352
            FIXME("command 0x%02x, no data transfer specified, but buflen is %d!!!\n",lpPRB->CDBByte[0],lpPRB->SRB_BufLen);
353 354 355
	}
	break;
  }
356
  ASPI_DebugPrintCmd(lpPRB);
357

Alexandre Julliard's avatar
Alexandre Julliard committed
358 359 360 361 362 363
  sg_hd = NULL;
  sg_reply_hdr = NULL;

  lpPRB->SRB_Status = SS_PENDING;

  if (!lpPRB->SRB_CDBLen) {
364
      ERR("Failed: lpPRB->SRB_CDBLen = 0.\n");
365
      return WNASPI32_DoPosting( lpPRB, SS_INVALID_SRB );
Alexandre Julliard's avatar
Alexandre Julliard committed
366 367 368 369 370 371
  }

  /* build up sg_header + scsi cmd */
  if (HOST_TO_TARGET(lpPRB)) {
    /* send header, command, and then data */
    in_len = SCSI_OFF + lpPRB->SRB_CDBLen + lpPRB->SRB_BufLen;
372
    sg_hd = HeapAlloc(GetProcessHeap(), 0, in_len);
Alexandre Julliard's avatar
Alexandre Julliard committed
373 374 375 376 377 378 379 380 381
    memset(sg_hd, 0, SCSI_OFF);
    memcpy(sg_hd + 1, &lpPRB->CDBByte[0], lpPRB->SRB_CDBLen);
    if (lpPRB->SRB_BufLen) {
      memcpy(((BYTE *) sg_hd) + SCSI_OFF + lpPRB->SRB_CDBLen, lpPRB->SRB_BufPointer, lpPRB->SRB_BufLen);
    }
  }
  else {
    /* send header and command - no data */
    in_len = SCSI_OFF + lpPRB->SRB_CDBLen;
382
    sg_hd = HeapAlloc(GetProcessHeap(), 0, in_len);
Alexandre Julliard's avatar
Alexandre Julliard committed
383 384 385 386 387 388
    memset(sg_hd, 0, SCSI_OFF);
    memcpy(sg_hd + 1, &lpPRB->CDBByte[0], lpPRB->SRB_CDBLen);
  }

  if (TARGET_TO_HOST(lpPRB)) {
    out_len = SCSI_OFF + lpPRB->SRB_BufLen;
389
    sg_reply_hdr = HeapAlloc(GetProcessHeap(), 0, out_len);
Alexandre Julliard's avatar
Alexandre Julliard committed
390 391 392 393 394
    memset(sg_reply_hdr, 0, SCSI_OFF);
    sg_hd->reply_len = out_len;
  }
  else {
    out_len = SCSI_OFF;
395
    sg_reply_hdr = HeapAlloc(GetProcessHeap(), 0, out_len);
Alexandre Julliard's avatar
Alexandre Julliard committed
396 397 398 399
    memset(sg_reply_hdr, 0, SCSI_OFF);
    sg_hd->reply_len = out_len;
  }

400 401
  SCSI_Fix_CMD_LEN(fd, lpPRB->CDBByte[0], lpPRB->SRB_CDBLen);

402 403 404 405 406
  if(!SCSI_LinuxDeviceIo( fd,
			  sg_hd, in_len,
			  sg_reply_hdr, out_len,
			  &status) )
  {
Alexandre Julliard's avatar
Alexandre Julliard committed
407 408 409 410 411
    goto error_exit;
  }

  if (sg_reply_hdr->result != 0) {
    error_code = sg_reply_hdr->result;
412
    WARN("reply header error (%d)\n", sg_reply_hdr->result);
Alexandre Julliard's avatar
Alexandre Julliard committed
413 414 415 416 417 418 419 420 421 422 423 424 425
    goto error_exit;
  }

  if (TARGET_TO_HOST(lpPRB) && lpPRB->SRB_BufLen) {
    memcpy(lpPRB->SRB_BufPointer, sg_reply_hdr + 1, lpPRB->SRB_BufLen);
  }

  /* copy in sense buffer to amount that is available in client */
  if (lpPRB->SRB_SenseLen) {
    int sense_len = lpPRB->SRB_SenseLen;
    if (lpPRB->SRB_SenseLen > 16)
      sense_len = 16;

426
    /* CDB is fixed in WNASPI32 */
427
    memcpy(lpPRB->SenseArea, &sg_reply_hdr->sense_buffer[0], sense_len);
428

Andreas Mohr's avatar
Andreas Mohr committed
429
    ASPI_PrintCDBArea(lpPRB);
430 431
    ASPI_PrintSenseArea(lpPRB);
  }
Alexandre Julliard's avatar
Alexandre Julliard committed
432

433
  SRB_Status = SS_COMP;
Alexandre Julliard's avatar
Alexandre Julliard committed
434
  lpPRB->SRB_HaStat = HASTAT_OK;
435 436
  lpPRB->SRB_TargStat = sg_reply_hdr->target_status << 1;

437 438 439
  HeapFree(GetProcessHeap(), 0, sg_reply_hdr);
  HeapFree(GetProcessHeap(), 0, sg_hd);

440
  /* FIXME: Should this be != 0 maybe? */
441
  if( lpPRB->SRB_TargStat == 2 ) {
442
    SRB_Status = SS_ERR;
443 444 445 446 447 448 449 450 451
    switch (lpPRB->CDBByte[0]) {
    case 0xa4: /* REPORT_KEY (DVD) MMC-2 */
    case 0xa3: /* SEND KEY (DVD) MMC-2 */
          SRB_Status = SS_COMP;
	  lpPRB->SRB_TargStat = 0;
	  FIXME("Program wants to do DVD Region switching, but fails (non compliant DVD drive). Ignoring....\n");
	  break;
    }
  }
Alexandre Julliard's avatar
Alexandre Julliard committed
452

453
  ASPI_DebugPrintResult(lpPRB);
Alexandre Julliard's avatar
Alexandre Julliard committed
454
  /* now do posting */
455 456 457 458 459 460 461 462
  ret = WNASPI32_DoPosting( lpPRB, SRB_Status );

  switch (lpPRB->CDBByte[0]) {
  case CMD_INQUIRY:
      if (SRB_Status == SS_COMP)
	  return SS_COMP; /* some junk expects ss_comp here. */
      /*FALLTHROUGH*/
  default:
463
      break;
464 465
  }

466 467
  /* In real WNASPI32 stuff really is always pending because ASPI does things
     in the background, but we are not doing that (yet) */
468 469

  return ret;
470

Alexandre Julliard's avatar
Alexandre Julliard committed
471
error_exit:
472
  SRB_Status = SS_ERR;
Alexandre Julliard's avatar
Alexandre Julliard committed
473
  if (error_code == EBUSY) {
474
      WNASPI32_DoPosting( lpPRB, SS_ASPI_IS_BUSY );
475
      TRACE("Device busy\n");
476 477
  } else
      FIXME("Failed\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
478 479 480 481

  /* I'm not sure exactly error codes work here
   * We probably should set lpPRB->SRB_TargStat, SRB_HaStat ?
   */
482
  WARN("error_exit\n");
483 484
  HeapFree(GetProcessHeap(), 0, sg_reply_hdr);
  HeapFree(GetProcessHeap(), 0, sg_hd);
485 486
  WNASPI32_DoPosting( lpPRB, SRB_Status );
  return SS_PENDING;
Alexandre Julliard's avatar
Alexandre Julliard committed
487
}
488 489

#endif /* defined(linux) */
Alexandre Julliard's avatar
Alexandre Julliard committed
490 491 492


/*******************************************************************
493
 *     GetASPI32SupportInfo		[WNASPI32.1]
Alexandre Julliard's avatar
Alexandre Julliard committed
494 495 496 497 498 499
 *
 * Checks if the ASPI subsystem is initialized correctly.
 *
 * RETURNS
 *    HIWORD: 0.
 *    HIBYTE of LOWORD: status (SS_COMP or SS_FAILED_INIT)
500
 *    LOBYTE of LOWORD: # of host adapters.
Alexandre Julliard's avatar
Alexandre Julliard committed
501
 */
502
DWORD __cdecl GetASPI32SupportInfo(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
503
{
504
    DWORD controllers = ASPI_GetNumControllers();
Alexandre Julliard's avatar
Alexandre Julliard committed
505

506 507 508 509
    if (!controllers)
	return SS_NO_ADAPTERS << 8;
    return (SS_COMP << 8) | controllers ;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
510 511

/***********************************************************************
512
 *             SendASPI32Command (WNASPI32.2)
Alexandre Julliard's avatar
Alexandre Julliard committed
513
 */
514
DWORD __cdecl SendASPI32Command(LPSRB lpSRB)
Alexandre Julliard's avatar
Alexandre Julliard committed
515 516
{
#ifdef linux
Mike McCormack's avatar
Mike McCormack committed
517 518
  static const char szId[] = "ASPI for WIN32";
  static const char szWh[] = "Wine host";
Alexandre Julliard's avatar
Alexandre Julliard committed
519 520 521
  switch (lpSRB->common.SRB_Cmd) {
  case SC_HA_INQUIRY:
    lpSRB->inquiry.SRB_Status = SS_COMP;       /* completed successfully */
522
    lpSRB->inquiry.HA_Count = ASPI_GetNumControllers();
Alexandre Julliard's avatar
Alexandre Julliard committed
523
    lpSRB->inquiry.HA_SCSI_ID = 7;             /* not always ID 7 */
Mike McCormack's avatar
Mike McCormack committed
524 525
    memcpy(lpSRB->inquiry.HA_ManagerId, szId, sizeof szId); /* max 15 chars, don't change */
    memcpy(lpSRB->inquiry.HA_Identifier, szWh, sizeof szWh); /* FIXME: return host adapter name */
Alexandre Julliard's avatar
Alexandre Julliard committed
526 527
    memset(lpSRB->inquiry.HA_Unique, 0, 16); /* default HA_Unique content */
    lpSRB->inquiry.HA_Unique[6] = 0x02; /* Maximum Transfer Length (128K, Byte> 4-7) */
528
    lpSRB->inquiry.HA_Unique[3] = 0x08; /* Maximum number of SCSI targets */
529
    FIXME("ASPI: Partially implemented SC_HA_INQUIRY for adapter %d.\n", lpSRB->inquiry.SRB_HaId);
Alexandre Julliard's avatar
Alexandre Julliard committed
530
    return SS_COMP;
531

Marcus Meissner's avatar
Marcus Meissner committed
532
  case SC_GET_DEV_TYPE: {
533 534
    /* FIXME: We should return SS_NO_DEVICE if the device is not configured */
    /* FIXME: We should return SS_INVALID_HA if HostAdapter!=0 */
Marcus Meissner's avatar
Marcus Meissner committed
535
    SRB		tmpsrb;
Mike McCormack's avatar
Mike McCormack committed
536
    unsigned char inqbuf[200];
537
    DWORD	ret;
Marcus Meissner's avatar
Marcus Meissner committed
538 539 540

    memset(&tmpsrb,0,sizeof(tmpsrb));

541
    /* Copy header */
542
    tmpsrb.common = lpSRB->common;
543

544 545 546 547
    tmpsrb.cmd.SRB_Flags	|= 8; /* target to host */
    tmpsrb.cmd.SRB_Cmd 		= SC_EXEC_SCSI_CMD;
    tmpsrb.cmd.SRB_Target	= lpSRB->devtype.SRB_Target;
    tmpsrb.cmd.SRB_Lun		= lpSRB->devtype.SRB_Lun;
Marcus Meissner's avatar
Marcus Meissner committed
548 549 550
    tmpsrb.cmd.SRB_BufLen	= sizeof(inqbuf);
    tmpsrb.cmd.SRB_BufPointer	= inqbuf;
    tmpsrb.cmd.CDBByte[0]	= 0x12; /* INQUIRY  */
551
    				  /* FIXME: handle lun */
Marcus Meissner's avatar
Marcus Meissner committed
552 553
    tmpsrb.cmd.CDBByte[4]	= sizeof(inqbuf);
    tmpsrb.cmd.SRB_CDBLen	= 6;
554

555
    ret = ASPI_ExecScsiCmd(&tmpsrb.cmd);
556 557

    lpSRB->devtype.SRB_Status	= tmpsrb.cmd.SRB_Status;
558
    lpSRB->devtype.SRB_DeviceType = inqbuf[0]&0x1f;
559

560
    TRACE("returning devicetype %d for target %d\n",inqbuf[0]&0x1f,tmpsrb.cmd.SRB_Target);
561 562 563 564
    if (ret!=SS_PENDING) /* Any error is passed down directly */
	return ret;
    /* FIXME: knows that the command is finished already, pass final Status */
    return tmpsrb.cmd.SRB_Status;
Marcus Meissner's avatar
Marcus Meissner committed
565
  }
Alexandre Julliard's avatar
Alexandre Julliard committed
566
  case SC_EXEC_SCSI_CMD:
567
    return ASPI_ExecScsiCmd(&lpSRB->cmd);
568 569 570
  case SC_ABORT_SRB:
    FIXME("Not implemented SC_ABORT_SRB\n");
    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
571
  case SC_RESET_DEV:
572
    FIXME("Not implemented SC_RESET_DEV\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
573
    break;
574
  case SC_GET_DISK_INFO:
575
    /* here we have to find out the int13 / bios association.
576 577 578 579 580
     * We just say we do not have any.
     */
    FIXME("SC_GET_DISK_INFO always return 'int13 unassociated disk'.\n");
    lpSRB->diskinfo.SRB_DriveFlags = 0; /* disk is not int13 served */
    return SS_COMP;
Alexandre Julliard's avatar
Alexandre Julliard committed
581
  default:
582
    FIXME("Unknown command %d\n", lpSRB->common.SRB_Cmd);
Alexandre Julliard's avatar
Alexandre Julliard committed
583 584 585 586 587 588 589 590 591
  }
  return SS_INVALID_SRB;
#else
  return SS_INVALID_SRB;
#endif
}


/***********************************************************************
592
 *             GetASPI32DLLVersion   (WNASPI32.4)
Alexandre Julliard's avatar
Alexandre Julliard committed
593
 */
594
DWORD __cdecl GetASPI32DLLVersion(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
595 596
{
#ifdef linux
597
	TRACE("Returning version 1\n");
598
        return 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
599
#else
600
	FIXME("Please add SCSI support for your operating system, returning 0\n");
601
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
602 603 604
#endif
}

605
/***********************************************************************
606
 *             GetASPI32Buffer   (WNASPI32.8)
607
 * Supposed to return a DMA capable large SCSI buffer.
608
 * Our implementation does not use those at all, all buffer stuff is
609
 * done in the kernel SG device layer. So we just heapalloc the buffer.
610
 */
611
BOOL __cdecl GetASPI32Buffer(PASPI32BUFF pab)
612
{
613 614 615 616 617
    pab->AB_BufPointer = HeapAlloc(GetProcessHeap(),
	    	pab->AB_ZeroFill?HEAP_ZERO_MEMORY:0,
		pab->AB_BufLen
    );
    if (!pab->AB_BufPointer) return FALSE;
618 619 620
    return TRUE;
}

621
/***********************************************************************
622
 *             FreeASPI32Buffer   (WNASPI32.14)
623
 */
624
BOOL __cdecl FreeASPI32Buffer(PASPI32BUFF pab)
625
{
626
    HeapFree(GetProcessHeap(),0,pab->AB_BufPointer);
627 628 629
    return TRUE;
}

630
/***********************************************************************
631
 *             TranslateASPI32Address   (WNASPI32.7)
632
 */
633 634 635 636 637
BOOL __cdecl TranslateASPI32Address(LPDWORD pdwPath, LPDWORD pdwDEVNODE)
{
    FIXME("(%p, %p), stub !\n", pdwPath, pdwDEVNODE);
    return TRUE;
}