17 #include "selectors.h"
23 * 1) Residual byte length reporting not handled
24 * 2) Make this code re-entrant for multithreading
25 * 3) Only linux supported so far
30 ASPI_OpenDevice16(SRB_ExecSCSICmd16
*prb
)
35 ASPI_DEVICE_INFO
*curr
;
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.
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
) {
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
);
53 if (!PROFILE_GetWineIniString(idstr
, "Device", "", device_str
, sizeof(device_str
))) {
54 TRACE(aspi
, "Trying to open unlisted scsi device %s\n", idstr
);
58 TRACE(aspi
, "Opening device %s=%s\n", idstr
, device_str
);
60 fd
= open(device_str
, O_RDWR
);
62 int save_error
= errno
;
64 ERR(aspi
, "Error opening device %s, error '%s'\n", device_str
, strerror(save_error
));
66 ERR(aspi
, "Error opening device %s, error %d\n", device_str
, save_error
);
71 /* device is now open */
72 curr
= HeapAlloc( SystemHeap
, 0, sizeof(ASPI_DEVICE_INFO
) );
74 curr
->hostId
= prb
->SRB_HaId
;
75 curr
->target
= prb
->SRB_Target
;
76 curr
->lun
= prb
->SRB_Lun
;
78 /* insert new record at beginning of open device list */
79 curr
->next
= ASPI_open_devices
;
80 ASPI_open_devices
= curr
;
86 ASPI_DebugPrintCmd(SRB_ExecSCSICmd16
*prb
, UINT16 mode
)
92 dbg_decl_str(aspi
, 512);
97 /* translate real mode address */
98 if (prb
->SRB_BufPointer
)
99 lpBuf
= (BYTE
*)DOSMEM_MapRealToLinear((UINT32
)prb
->SRB_BufPointer
);
102 lpBuf
= PTR_SEG_TO_LIN(prb
->SRB_BufPointer
);
106 switch (prb
->CDBByte
[0]) {
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]);
117 TRACE(aspi
, "Transfer Length: %d\n", prb
->CDBByte
[4]);
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");
126 else if (HOST_TO_TARGET(prb
)) {
127 TRACE(aspi
, "\tData transfer: Host to target. Length checked.\n");
129 else if (NO_DATA_TRANSFERED(prb
)) {
130 TRACE(aspi
, "\tData transfer: none\n");
133 WARN(aspi
, "\tTransfer by scsi cmd. Length not checked\n");
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
++);
153 TRACE(aspi
, "CDB buffer[%s]\n", dbg_str(aspi
));
157 ASPI_PrintSenseArea16(SRB_ExecSCSICmd16
*prb
)
161 dbg_decl_str(aspi
, 512);
163 cdb
= &prb
->CDBByte
[0];
164 for (i
= 0; i
< prb
->SRB_SenseLen
; i
++) {
165 if (i
) dsprintf(aspi
, ",");
166 dsprintf(aspi
, "%02x", *cdb
++);
168 TRACE(aspi
, "SenseArea[%s]\n", dbg_str(aspi
));
172 ASPI_DebugPrintResult(SRB_ExecSCSICmd16
*prb
, UINT16 mode
)
179 /* translate real mode address */
180 if (prb
->SRB_BufPointer
)
181 lpBuf
= (BYTE
*)DOSMEM_MapRealToLinear((UINT32
)prb
->SRB_BufPointer
);
184 lpBuf
= PTR_SEG_TO_LIN(prb
->SRB_BufPointer
);
188 switch (prb
->CDBByte
[0]) {
190 TRACE(aspi
, "Vendor: '%s'\n", lpBuf
+ INQUIRY_VENDOR
);
192 case CMD_TEST_UNIT_READY
:
193 ASPI_PrintSenseArea16(prb
);
199 ASPI_ExecScsiCmd(DWORD ptrPRB
, UINT16 mode
)
201 SRB_ExecSCSICmd16
*lpPRB
= 0;
202 struct sg_header
*sg_hd
, *sg_reply_hdr
;
213 lpPRB
= (SRB_ExecSCSICmd16
*)DOSMEM_MapRealToLinear(ptrPRB
);
216 lpPRB
= PTR_SEG_TO_LIN(ptrPRB
);
220 ASPI_DebugPrintCmd(lpPRB
, mode
);
222 fd
= ASPI_OpenDevice16(lpPRB
);
224 ERR(aspi
, "Failed: could not open device. Device permissions !?\n");
225 lpPRB
->SRB_Status
= SS_ERR
;
232 lpPRB
->SRB_Status
= SS_PENDING
;
237 /* translate real mode address */
239 lpBuf
= (BYTE
*)DOSMEM_MapRealToLinear((UINT32
)lpPRB
->SRB_BufPointer
);
242 lpBuf
= PTR_SEG_TO_LIN(lpPRB
->SRB_BufPointer
);
246 if (!lpPRB
->SRB_CDBLen
) {
247 WARN(aspi
, "Failed: lpPRB->SRB_CDBLen = 0.\n");
248 lpPRB
->SRB_Status
= SS_ERR
;
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
);
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
);
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
;
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
;
284 status
= write(fd
, sg_hd
, in_len
);
285 if (status
< 0 || status
!= in_len
) {
286 int save_error
= errno
;
288 WARN(aspi
, "Not enough bytes written to scsi device bytes=%d .. %d\n", in_len
, status
);
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");
294 WARN(aspi
, "error:= '%s'\n", strerror(save_error
));
296 WARN(aspi
, "error:= %d\n", save_error
);
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
);
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
);
314 if (TARGET_TO_HOST(lpPRB
) && lpPRB
->SRB_BufLen
) {
315 memcpy(lpBuf
, sg_reply_hdr
+ 1, lpPRB
->SRB_BufLen
);
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)
323 memcpy(SENSE_BUFFER(lpPRB
), &sg_reply_hdr
->sense_buffer
[0], sense_len
);
327 lpPRB
->SRB_Status
= SS_COMP
;
328 lpPRB
->SRB_HaStat
= HASTAT_OK
;
329 lpPRB
->SRB_TargStat
= STATUS_GOOD
;
333 if (ASPI_POSTING(lpPRB
) && lpPRB
->SRB_PostProc
) {
334 TRACE(aspi
, "Post Routine (%lx) called\n", (DWORD
) lpPRB
->SRB_PostProc
);
339 SEGPTR spPRB
= MapLS(lpPRB
);
341 Callbacks
->CallASPIPostProc(lpPRB
->SRB_PostProc
, spPRB
);
346 Callbacks
->CallASPIPostProc(lpPRB
->SRB_PostProc
, ptrPRB
);
353 ASPI_DebugPrintResult(lpPRB
, mode
);
357 if (error_code
== EBUSY
) {
358 lpPRB
->SRB_Status
= SS_ASPI_IS_BUSY
;
359 TRACE(aspi
, "Device busy\n");
362 WARN(aspi
, "Failed\n");
363 lpPRB
->SRB_Status
= SS_ERR
;
366 /* I'm not sure exactly error codes work here
367 * We probably should set lpPRB->SRB_TargStat, SRB_HaStat ?
369 WARN(aspi
, "error_exit\n");
372 return lpPRB
->SRB_Status
;
377 /***********************************************************************
378 * GetASPISupportInfo16 (WINASPI.1)
381 WORD WINAPI
GetASPISupportInfo16()
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.
389 return ((SS_COMP
<< 8) | 1);
391 return ((SS_COMP
<< 8) | 0);
396 DWORD
ASPI_SendASPICommand(DWORD ptrSRB
, UINT16 mode
)
405 lpSRB
= (LPSRB16
)DOSMEM_MapRealToLinear(ptrSRB
);
408 lpSRB
= PTR_SEG_TO_LIN(ptrSRB
);
412 switch (lpSRB
->common
.SRB_Cmd
) {
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");
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
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
);
428 case SC_GET_DEV_TYPE
:
429 FIXME(aspi
, "Not implemented SC_GET_DEV_TYPE\n");
431 case SC_EXEC_SCSI_CMD
:
432 return ASPI_ExecScsiCmd((DWORD
)ptrSRB
, mode
);
435 FIXME(aspi
, "Not implemented SC_RESET_DEV\n");
438 WARN(aspi
, "Unknown command %d\n", lpSRB
->common
.SRB_Cmd
);
440 return SS_INVALID_SRB
;
442 return SS_INVALID_SRB
;
447 /***********************************************************************
448 * SendASPICommand16 (WINASPI.2)
450 WORD WINAPI
SendASPICommand16(SEGPTR segptr_srb
)
453 return ASPI_SendASPICommand(segptr_srb
, ASPI_WIN16
);
460 /***********************************************************************
461 * GetASPIDLLVersion16 (WINASPI.4)
464 DWORD WINAPI
GetASPIDLLVersion16()
474 void WINAPI
ASPI_DOS_func(CONTEXT
*context
)
476 WORD
*stack
= CTX_SEG_OFF_TO_LIN(context
, SS_reg(context
), ESP_reg(context
));
477 DWORD ptrSRB
= *(DWORD
*)&stack
[2];
479 ASPI_SendASPICommand(ptrSRB
, ASPI_DOS
);
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
);
488 /* returns the address of a real mode callback to ASPI_DOS_func() */
489 void ASPI_DOS_HandleInt(CONTEXT
*context
)
492 FARPROC16
*p
= (FARPROC16
*)CTX_SEG_OFF_TO_LIN(context
, DS_reg(context
), EDX_reg(context
));
493 *p
= DPMI_AllocInternalRMCB(ASPI_DOS_func
);
494 TRACE(aspi
, "allocated real mode proc %p\n", *p
);