17 #include "selectors.h"
22 * 1) Residual byte length reporting not handled
23 * 2) Make this code re-entrant for multithreading
24 * 3) Only linux supported so far
29 ASPI_OpenDevice16(SRB_ExecSCSICmd16
*prb
)
34 ASPI_DEVICE_INFO
*curr
;
36 /* search list of devices to see if we've opened it already.
37 * There is not an explicit open/close in ASPI land, so hopefully
38 * keeping a device open won't be a problem.
41 for (curr
= ASPI_open_devices
; curr
; curr
= curr
->next
) {
42 if (curr
->hostId
== prb
->SRB_HaId
&&
43 curr
->target
== prb
->SRB_Target
&&
44 curr
->lun
== prb
->SRB_Lun
) {
49 /* device wasn't cached, go ahead and open it */
50 sprintf(idstr
, "scsi c%1dt%1dd%1d", prb
->SRB_HaId
, prb
->SRB_Target
, prb
->SRB_Lun
);
52 if (!PROFILE_GetWineIniString(idstr
, "Device", "", device_str
, sizeof(device_str
))) {
53 TRACE(aspi
, "Trying to open unlisted scsi device %s\n", idstr
);
57 TRACE(aspi
, "Opening device %s=%s\n", idstr
, device_str
);
59 fd
= open(device_str
, O_RDWR
);
61 int save_error
= errno
;
63 ERR(aspi
, "Error opening device %s, error '%s'\n", device_str
, strerror(save_error
));
65 ERR(aspi
, "Error opening device %s, error %d\n", device_str
, save_error
);
70 /* device is now open */
71 curr
= HeapAlloc( SystemHeap
, 0, sizeof(ASPI_DEVICE_INFO
) );
73 curr
->hostId
= prb
->SRB_HaId
;
74 curr
->target
= prb
->SRB_Target
;
75 curr
->lun
= prb
->SRB_Lun
;
77 /* insert new record at beginning of open device list */
78 curr
->next
= ASPI_open_devices
;
79 ASPI_open_devices
= curr
;
85 ASPI_DebugPrintCmd(SRB_ExecSCSICmd16
*prb
, UINT16 mode
)
91 dbg_decl_str(aspi
, 512);
96 /* translate real mode address */
97 if (prb
->SRB_BufPointer
)
98 lpBuf
= (BYTE
*)DOSMEM_MapRealToLinear((UINT
)prb
->SRB_BufPointer
);
101 lpBuf
= PTR_SEG_TO_LIN(prb
->SRB_BufPointer
);
105 switch (prb
->CDBByte
[0]) {
108 TRACE(aspi
, "\tEVPD: %d\n", prb
->CDBByte
[1] & 1);
109 TRACE(aspi
, "\tLUN: %d\n", (prb
->CDBByte
[1] & 0xc) >> 1);
110 TRACE(aspi
, "\tPAGE CODE: %d\n", prb
->CDBByte
[2]);
111 TRACE(aspi
, "\tALLOCATION LENGTH: %d\n", prb
->CDBByte
[4]);
112 TRACE(aspi
, "\tCONTROL: %d\n", prb
->CDBByte
[5]);
116 TRACE(aspi
, "Transfer Length: %d\n", prb
->CDBByte
[4]);
120 TRACE(aspi
, "Host Adapter: %d\n", prb
->SRB_HaId
);
121 TRACE(aspi
, "Flags: %d\n", prb
->SRB_Flags
);
122 if (TARGET_TO_HOST(prb
)) {
123 TRACE(aspi
, "\tData transfer: Target to host. Length checked.\n");
125 else if (HOST_TO_TARGET(prb
)) {
126 TRACE(aspi
, "\tData transfer: Host to target. Length checked.\n");
128 else if (NO_DATA_TRANSFERED(prb
)) {
129 TRACE(aspi
, "\tData transfer: none\n");
132 WARN(aspi
, "\tTransfer by scsi cmd. Length not checked\n");
135 TRACE(aspi
, "\tResidual byte length reporting %s\n", prb
->SRB_Flags
& 0x4 ? "enabled" : "disabled");
136 TRACE(aspi
, "\tLinking %s\n", prb
->SRB_Flags
& 0x2 ? "enabled" : "disabled");
137 TRACE(aspi
, "\tPosting %s\n", prb
->SRB_Flags
& 0x1 ? "enabled" : "disabled");
138 TRACE(aspi
, "Target: %d\n", prb
->SRB_Target
);
139 TRACE(aspi
, "Lun: %d\n", prb
->SRB_Lun
);
140 TRACE(aspi
, "BufLen: %ld\n", prb
->SRB_BufLen
);
141 TRACE(aspi
, "SenseLen: %d\n", prb
->SRB_SenseLen
);
142 TRACE(aspi
, "BufPtr: %lx (%p)\n", prb
->SRB_BufPointer
, lpBuf
);
143 TRACE(aspi
, "LinkPointer %lx\n", prb
->SRB_Rsvd1
);
144 TRACE(aspi
, "CDB Length: %d\n", prb
->SRB_CDBLen
);
145 TRACE(aspi
, "POST Proc: %lx\n", (DWORD
) prb
->SRB_PostProc
);
146 cdb
= &prb
->CDBByte
[0];
147 cmd
= prb
->CDBByte
[0];
148 for (i
= 0; i
< prb
->SRB_CDBLen
; i
++) {
149 if (i
!= 0) dsprintf(aspi
, ",");
150 dsprintf(aspi
, "%02x", *cdb
++);
152 TRACE(aspi
, "CDB buffer[%s]\n", dbg_str(aspi
));
156 ASPI_PrintSenseArea16(SRB_ExecSCSICmd16
*prb
)
160 dbg_decl_str(aspi
, 512);
162 cdb
= &prb
->CDBByte
[0];
163 for (i
= 0; i
< prb
->SRB_SenseLen
; i
++) {
164 if (i
) dsprintf(aspi
, ",");
165 dsprintf(aspi
, "%02x", *cdb
++);
167 TRACE(aspi
, "SenseArea[%s]\n", dbg_str(aspi
));
171 ASPI_DebugPrintResult(SRB_ExecSCSICmd16
*prb
, UINT16 mode
)
178 /* translate real mode address */
179 if (prb
->SRB_BufPointer
)
180 lpBuf
= (BYTE
*)DOSMEM_MapRealToLinear((UINT
)prb
->SRB_BufPointer
);
183 lpBuf
= PTR_SEG_TO_LIN(prb
->SRB_BufPointer
);
187 switch (prb
->CDBByte
[0]) {
189 TRACE(aspi
, "Vendor: '%s'\n", lpBuf
+ INQUIRY_VENDOR
);
191 case CMD_TEST_UNIT_READY
:
192 ASPI_PrintSenseArea16(prb
);
198 ASPI_ExecScsiCmd(DWORD ptrPRB
, UINT16 mode
)
200 SRB_ExecSCSICmd16
*lpPRB
= 0;
201 struct sg_header
*sg_hd
, *sg_reply_hdr
;
212 lpPRB
= (SRB_ExecSCSICmd16
*)DOSMEM_MapRealToLinear(ptrPRB
);
215 lpPRB
= PTR_SEG_TO_LIN(ptrPRB
);
219 ASPI_DebugPrintCmd(lpPRB
, mode
);
221 fd
= ASPI_OpenDevice16(lpPRB
);
223 WARN(aspi
, "Failed: could not open device. Device permissions !?\n");
224 lpPRB
->SRB_Status
= SS_ERR
;
231 lpPRB
->SRB_Status
= SS_PENDING
;
236 /* translate real mode address */
238 lpBuf
= (BYTE
*)DOSMEM_MapRealToLinear((UINT
)lpPRB
->SRB_BufPointer
);
241 lpBuf
= PTR_SEG_TO_LIN(lpPRB
->SRB_BufPointer
);
245 if (!lpPRB
->SRB_CDBLen
) {
246 WARN(aspi
, "Failed: lpPRB->SRB_CDBLen = 0.\n");
247 lpPRB
->SRB_Status
= SS_ERR
;
251 /* build up sg_header + scsi cmd */
252 if (HOST_TO_TARGET(lpPRB
)) {
253 /* send header, command, and then data */
254 in_len
= SCSI_OFF
+ lpPRB
->SRB_CDBLen
+ lpPRB
->SRB_BufLen
;
255 sg_hd
= (struct sg_header
*) malloc(in_len
);
256 memset(sg_hd
, 0, SCSI_OFF
);
257 memcpy(sg_hd
+ 1, &lpPRB
->CDBByte
[0], lpPRB
->SRB_CDBLen
);
258 if (lpPRB
->SRB_BufLen
) {
259 memcpy(((BYTE
*) sg_hd
) + SCSI_OFF
+ lpPRB
->SRB_CDBLen
, lpBuf
, lpPRB
->SRB_BufLen
);
263 /* send header and command - no data */
264 in_len
= SCSI_OFF
+ lpPRB
->SRB_CDBLen
;
265 sg_hd
= (struct sg_header
*) malloc(in_len
);
266 memset(sg_hd
, 0, SCSI_OFF
);
267 memcpy(sg_hd
+ 1, &lpPRB
->CDBByte
[0], lpPRB
->SRB_CDBLen
);
270 if (TARGET_TO_HOST(lpPRB
)) {
271 out_len
= SCSI_OFF
+ lpPRB
->SRB_BufLen
;
272 sg_reply_hdr
= (struct sg_header
*) malloc(out_len
);
273 memset(sg_reply_hdr
, 0, SCSI_OFF
);
274 sg_hd
->reply_len
= out_len
;
278 sg_reply_hdr
= (struct sg_header
*) malloc(out_len
);
279 memset(sg_reply_hdr
, 0, SCSI_OFF
);
280 sg_hd
->reply_len
= out_len
;
283 status
= write(fd
, sg_hd
, in_len
);
284 if (status
< 0 || status
!= in_len
) {
285 int save_error
= errno
;
287 WARN(aspi
, "Not enough bytes written to scsi device bytes=%d .. %d\n", in_len
, status
);
289 if (save_error
== ENOMEM
) {
290 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");
293 WARN(aspi
, "error:= '%s'\n", strerror(save_error
));
295 WARN(aspi
, "error:= %d\n", save_error
);
301 status
= read(fd
, sg_reply_hdr
, out_len
);
302 if (status
< 0 || status
!= out_len
) {
303 WARN(aspi
, "not enough bytes read from scsi device%d\n", status
);
307 if (sg_reply_hdr
->result
!= 0) {
308 error_code
= sg_reply_hdr
->result
;
309 WARN(aspi
, "reply header error (%d)\n", sg_reply_hdr
->result
);
313 if (TARGET_TO_HOST(lpPRB
) && lpPRB
->SRB_BufLen
) {
314 memcpy(lpBuf
, sg_reply_hdr
+ 1, lpPRB
->SRB_BufLen
);
317 /* copy in sense buffer to amount that is available in client */
318 if (lpPRB
->SRB_SenseLen
) {
319 int sense_len
= lpPRB
->SRB_SenseLen
;
320 if (lpPRB
->SRB_SenseLen
> 16)
322 memcpy(SENSE_BUFFER(lpPRB
), &sg_reply_hdr
->sense_buffer
[0], sense_len
);
326 lpPRB
->SRB_Status
= SS_COMP
;
327 lpPRB
->SRB_HaStat
= HASTAT_OK
;
328 lpPRB
->SRB_TargStat
= STATUS_GOOD
;
332 if (ASPI_POSTING(lpPRB
) && lpPRB
->SRB_PostProc
) {
333 TRACE(aspi
, "Post Routine (%lx) called\n", (DWORD
) lpPRB
->SRB_PostProc
);
338 SEGPTR spPRB
= MapLS(lpPRB
);
340 Callbacks
->CallASPIPostProc(lpPRB
->SRB_PostProc
, spPRB
);
345 Callbacks
->CallASPIPostProc(lpPRB
->SRB_PostProc
, ptrPRB
);
352 ASPI_DebugPrintResult(lpPRB
, mode
);
356 if (error_code
== EBUSY
) {
357 lpPRB
->SRB_Status
= SS_ASPI_IS_BUSY
;
358 TRACE(aspi
, "Device busy\n");
361 WARN(aspi
, "Failed\n");
362 lpPRB
->SRB_Status
= SS_ERR
;
365 /* I'm not sure exactly error codes work here
366 * We probably should set lpPRB->SRB_TargStat, SRB_HaStat ?
368 WARN(aspi
, "error_exit\n");
371 return lpPRB
->SRB_Status
;
376 /***********************************************************************
377 * GetASPISupportInfo16 (WINASPI.1)
380 WORD WINAPI
GetASPISupportInfo16()
383 TRACE(aspi
, "GETASPISupportInfo16\n");
384 /* high byte SS_COMP - low byte number of host adapters.
385 * FIXME!!! The number of host adapters is incorrect.
386 * I'm not sure how to determine this under linux etc.
388 return ((SS_COMP
<< 8) | 1);
390 return ((SS_COMP
<< 8) | 0);
395 DWORD
ASPI_SendASPICommand(DWORD ptrSRB
, UINT16 mode
)
404 lpSRB
= (LPSRB16
)DOSMEM_MapRealToLinear(ptrSRB
);
407 lpSRB
= PTR_SEG_TO_LIN(ptrSRB
);
411 switch (lpSRB
->common
.SRB_Cmd
) {
413 lpSRB
->inquiry
.SRB_Status
= SS_COMP
; /* completed successfully */
414 if (lpSRB
->inquiry
.SRB_55AASignature
== 0x55aa) {
415 TRACE(aspi
, "Extended request detected (Adaptec's ASPIxDOS).\nWe don't support it at the moment.\n");
417 lpSRB
->inquiry
.SRB_ExtBufferSize
= 0x2000; /* bogus value */
418 lpSRB
->inquiry
.HA_Count
= 1; /* not always */
419 lpSRB
->inquiry
.HA_SCSI_ID
= 7; /* not always ID 7 */
420 strcat(lpSRB
->inquiry
.HA_ManagerId
, "Wine ASPI16"); /* max 15 chars */
421 strcat(lpSRB
->inquiry
.HA_Identifier
, "Wine host"); /* FIXME: return host
423 memset(lpSRB
->inquiry
.HA_Unique
, 0, 16); /* default HA_Unique content */
424 lpSRB
->inquiry
.HA_Unique
[6] = 0x02; /* Maximum Transfer Length (128K, Byte> 4-7) */
425 FIXME(aspi
, "ASPI: Partially implemented SC_HA_INQUIRY for adapter %d.\n", lpSRB
->inquiry
.SRB_HaId
);
427 case SC_GET_DEV_TYPE
:
428 FIXME(aspi
, "Not implemented SC_GET_DEV_TYPE\n");
430 case SC_EXEC_SCSI_CMD
:
431 return ASPI_ExecScsiCmd((DWORD
)ptrSRB
, mode
);
434 FIXME(aspi
, "Not implemented SC_RESET_DEV\n");
437 WARN(aspi
, "Unknown command %d\n", lpSRB
->common
.SRB_Cmd
);
439 return SS_INVALID_SRB
;
441 return SS_INVALID_SRB
;
446 /***********************************************************************
447 * SendASPICommand16 (WINASPI.2)
449 WORD WINAPI
SendASPICommand16(SEGPTR segptr_srb
)
452 return ASPI_SendASPICommand(segptr_srb
, ASPI_WIN16
);
459 /***********************************************************************
460 * GetASPIDLLVersion16 (WINASPI.4)
463 DWORD WINAPI
GetASPIDLLVersion16()
473 void WINAPI
ASPI_DOS_func(CONTEXT
*context
)
475 WORD
*stack
= CTX_SEG_OFF_TO_LIN(context
, SS_reg(context
), ESP_reg(context
));
476 DWORD ptrSRB
= *(DWORD
*)&stack
[2];
478 ASPI_SendASPICommand(ptrSRB
, ASPI_DOS
);
480 /* simulate a normal RETF sequence as required by DPMI CallRMProcFar */
481 IP_reg(context
) = *(stack
++);
482 CS_reg(context
) = *(stack
++);
483 SP_reg(context
) += 2*sizeof(WORD
);
487 /* returns the address of a real mode callback to ASPI_DOS_func() */
488 void ASPI_DOS_HandleInt(CONTEXT
*context
)
491 FARPROC16
*p
= (FARPROC16
*)CTX_SEG_OFF_TO_LIN(context
, DS_reg(context
), EDX_reg(context
));
492 if ((CX_reg(context
) == 4) || (CX_reg(context
) == 5))
494 *p
= DPMI_AllocInternalRMCB(ASPI_DOS_func
);
495 TRACE(aspi
, "allocated real mode proc %p\n", *p
);
496 AX_reg(context
) = CX_reg(context
);