/*********************************************************************** Copyright 2002 Ben Rudiak-Gould. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA, or visit . ***********************************************************************/ #include "scsi-miniport.h" #include "dvdproxy2k.h" #include "../include/dvdsynth-scsi.h" #define min(a,b) ((a)<(b)?(a):(b)) // The reason USER_LISTEN_TIMEOUT is set so small is that despite // my best efforts I cannot get the ScsiPort driver to acknowledge // the MultipleRequestPerLu or TaggedQueuing flags. As a result, // the dummy device cannot respond to an INQUIRY command until the // current listener (if any) has timed out. //static const unsigned TICK_LENGTH = 1000000; // in usec //static const UCHAR USER_LISTEN_TIMEOUT = 1; // in ticks //static const UCHAR USER_RESPONSE_TIMEOUT = 2; // in ticks #ifdef DBGLEVEL char* DebugFmtHex(char* p, unsigned x, int digits) { for (int i=digits-1; i>=0; --i) { p[i] = "0123456789abcdef"[x&15]; x >>= 4; } return p+digits; } const char* CDBString(const unsigned char* cdb, int cdblen) { static char buf[16*3]; if (cdblen < 0) cdblen = 0; if (cdblen > 16) cdblen = 16; char* p = buf; for (int i=0; i0) *p++ = ' '; p = DebugFmtHex(p, cdb[i], 2); } *p = 0; return buf; } #endif class SRBQueue { private: enum { SRB_QUEUE_SIZE = 16 }; // should be a power of 2 SCSI_REQUEST_BLOCK* q[SRB_QUEUE_SIZE]; ULONG retire, dispatch, incoming; // retire <= dispatch <= incoming public: void Clear() { retire = dispatch = incoming; } // void CompleteAll(DVDProxy* bus); bool AddIncomingSRB(SCSI_REQUEST_BLOCK* srb) { if (ULONG(incoming-retire) >= ULONG(SRB_QUEUE_SIZE)) { return false; } else { q[(incoming++)%SRB_QUEUE_SIZE] = srb; return true; } } SCSI_REQUEST_BLOCK* GetDispatchSRB(ULONG* index) { while (dispatch != incoming && q[dispatch%SRB_QUEUE_SIZE] == NULL) ++dispatch; if (dispatch == incoming) { return 0; } else { *index = dispatch; return q[(dispatch++)%SRB_QUEUE_SIZE]; } } void UngetDispatchSRB() { // dangerous unless called immediately after GetDispatchSRB --dispatch; } SCSI_REQUEST_BLOCK* RemoveRetireeByIndex(ULONG index) { if (ULONG(index-retire) >= ULONG(dispatch-retire)) { return 0; } else { SCSI_REQUEST_BLOCK* result = q[index%SRB_QUEUE_SIZE]; q[index%SRB_QUEUE_SIZE] = NULL; while (retire != dispatch && q[retire%SRB_QUEUE_SIZE] == NULL) ++retire; return result; } } bool RemoveSRB(SCSI_REQUEST_BLOCK* srb) { for (ULONG i = retire; i != incoming; ++i) { if (q[i%SRB_QUEUE_SIZE] == srb) { q[i%SRB_QUEUE_SIZE] = NULL; while (dispatch != incoming && q[dispatch%SRB_QUEUE_SIZE] == NULL) ++dispatch; while (retire != dispatch && q[retire%SRB_QUEUE_SIZE] == NULL) ++retire; return true; } } return false; } #ifdef DBGLEVEL char* DebugFmtString(char* p, const char* s) { while (*s) *p++ = *s++; return p; } void DebugPrintQueue() { char buf[20 + SRB_QUEUE_SIZE*10]; char* p = buf; p = DebugFmtString(p, "queue = "); for (ULONG i = retire; i != incoming; ++i) { if (i == dispatch) p = DebugFmtString(p, "| "); p = DebugFmtHex(p, (unsigned)q[i%SRB_QUEUE_SIZE], 8); *p++ = ' '; } if (incoming == dispatch) *p++ = '|'; *p = 0; DBGPRINT((DBGLEVEL buf)); } #endif }; static const SenseData default_sense = { 0x70, 0, 0, {0,0,0,0}, 10, {0,0,0,0}, 0, 0, 0, {0,0,0} }; struct DVDProxy { SRBQueue queue; SCSI_REQUEST_BLOCK* srb_listen; // user-mode app's listening SRB bool user_attached; UCHAR user_listen_countdown; // after this many ticks, fail the srb_listen SRB UCHAR user_response_countdown; // after this many ticks, assume the user app has died unsigned tick_length; InquiryData inquiry_data[31]; void Complete(SCSI_REQUEST_BLOCK* completed_srb); void CompleteWithScsiSense(SCSI_REQUEST_BLOCK* completed_srb, unsigned scsi_sense); void CompleteWithScsiSuccess(SCSI_REQUEST_BLOCK* completed_srb) { completed_srb->SrbStatus = SRB_STATUS_SUCCESS; completed_srb->ScsiStatus = SCSISTAT_GOOD; Complete(completed_srb); } void CompleteWithSrbStatus(SCSI_REQUEST_BLOCK* completed_srb, UCHAR srb_status) { completed_srb->SrbStatus = srb_status; completed_srb->ScsiStatus = SCSISTAT_GOOD; Complete(completed_srb); } static bool ConstructUserModeRequest(SCSI_REQUEST_BLOCK* src, ULONG sequence_number, SCSI_REQUEST_BLOCK* dst); static void UnpackUserModeResponse(SCSI_REQUEST_BLOCK* src, SCSI_REQUEST_BLOCK* dst); void CompleteWithData(SCSI_REQUEST_BLOCK* Srb, const unsigned char* data, unsigned len, unsigned alloc); void HandleSkeletonDevice(SCSI_REQUEST_BLOCK* Srb); void HandleDummyDevice(SCSI_REQUEST_BLOCK* Srb); void QueueSRB(SCSI_REQUEST_BLOCK* Srb); BOOLEAN ResetBus(ULONG PathId); BOOLEAN StartIo(SCSI_REQUEST_BLOCK* Srb); VOID ScsiTimer(); }; /* inline void SRBQueue::CompleteAll(DVDProxy* bus) { dispatch = incoming; while (retire != dispatch) { SCSI_REQUEST_BLOCK* srb = q[retire%SRB_QUEUE_SIZE] if (srb) bus->HandleSkeletonDevice(srb); ++retire; } } */ // timer proc is needed iff user_attached is true. // if user_attached goes to false, immediately fail all SRBs in the queue. VOID ZeroMemory(IN PVOID Buffer, IN ULONG Count) { for (ULONG i=0; iScsiTimer(); } BOOLEAN __stdcall HwStartIo(IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb) { return ((DVDProxy*)DeviceExtension)->StartIo(Srb); } BOOLEAN __stdcall HwResetBus(PVOID DeviceExtension, ULONG PathId) { return ((DVDProxy*)DeviceExtension)->ResetBus(PathId); } BOOLEAN __stdcall HwInitialize(IN PVOID DeviceExtension) { return TRUE; } ULONG HwFindAdapter( IN PVOID DeviceExtension, IN PVOID HwContext, IN PVOID BusInformation, IN PCHAR ArgumentString, IN OUT PORT_CONFIGURATION_INFORMATION* ConfigInfo, OUT PBOOLEAN Again ) { DBGPRINT((DBGLEVEL "HwFindAdapter: SystemIoBusNumber=%d, MaximumTransferLength=%d, NumberOfPhysicalBreaks=%d,\nNumberOfAccessRanges=%d, InitiatorBusId[0]=%d, ScatterGather=%d, MapBuffers=%d, BufferAccessScsiPortControlled=%d\n", ConfigInfo->SystemIoBusNumber, ConfigInfo->MaximumTransferLength, ConfigInfo->NumberOfPhysicalBreaks, ConfigInfo->NumberOfAccessRanges, ConfigInfo->InitiatorBusId[0], ConfigInfo->ScatterGather, ConfigInfo->MapBuffers, ConfigInfo->BufferAccessScsiPortControlled)); *Again = FALSE; ConfigInfo->NumberOfBuses = 1; ConfigInfo->MaximumNumberOfTargets = 32; const unsigned offsetof_MaximumNumberOfLogicalUnits = (char*)&ConfigInfo->MaximumNumberOfLogicalUnits - (char*)ConfigInfo; if (ConfigInfo->Length > offsetof_MaximumNumberOfLogicalUnits) ConfigInfo->MaximumNumberOfLogicalUnits = 1; return SP_RETURN_FOUND; } SCSI_ADAPTER_CONTROL_STATUS HwAdapterControl( IN PVOID DeviceExtension, IN SCSI_ADAPTER_CONTROL_TYPE ControlType, IN PVOID Parameters ) { DBGPRINT((DBGLEVEL "AdapterControl(%d)\n", ControlType)); switch (ControlType) { case ScsiQuerySupportedControlTypes: { SCSI_SUPPORTED_CONTROL_TYPE_LIST* ssctl = (SCSI_SUPPORTED_CONTROL_TYPE_LIST*)Parameters; ZeroMemory(ssctl->SupportedTypeList, ssctl->MaxControlType); if (ScsiQuerySupportedControlTypes < ssctl->MaxControlType) ssctl->SupportedTypeList[ScsiQuerySupportedControlTypes] = TRUE; if (ScsiStopAdapter < ssctl->MaxControlType) ssctl->SupportedTypeList[ScsiStopAdapter] = TRUE; if (ScsiRestartAdapter < ssctl->MaxControlType) ssctl->SupportedTypeList[ScsiRestartAdapter] = TRUE; } // fall thru case ScsiStopAdapter: case ScsiRestartAdapter: return ScsiAdapterControlSuccess; default: return ScsiAdapterControlUnsuccessful; } } BOOLEAN DVDProxy::ResetBus(ULONG PathId) { DBGPRINT((DBGLEVEL "ResetBus(%d)\n", PathId)); ScsiPortCompleteRequest(this, (UCHAR)PathId, (UCHAR)SP_UNTAGGED, (UCHAR)SP_UNTAGGED, (UCHAR)SRB_STATUS_BUS_RESET); queue.Clear(); srb_listen = NULL; ScsiPortNotification(BusChangeDetected, this, 0); return TRUE; } // the standard says that for a single-byte transfer length 0 means 256 inline ULONG ScsiByteToInt(unsigned byte) { return byte ? byte : 256; } void DVDProxy::Complete(SCSI_REQUEST_BLOCK* completed_srb) { if (completed_srb->SenseInfoBufferLength >= 14) { DBGPRINT((DBGLEVEL "Srb %x complete with status %02x:%02x:%02x:%02x:%02x\n", completed_srb, completed_srb->SrbStatus, completed_srb->ScsiStatus, ((unsigned char*)completed_srb->SenseInfoBuffer)[2], ((unsigned char*)completed_srb->SenseInfoBuffer)[12], ((unsigned char*)completed_srb->SenseInfoBuffer)[13])); } else { DBGPRINT((DBGLEVEL "Srb %x complete with status %02x:%02x\n", completed_srb, completed_srb->SrbStatus, completed_srb->ScsiStatus)); } ScsiPortNotification(RequestComplete, this, completed_srb); } void DVDProxy::CompleteWithScsiSense(SCSI_REQUEST_BLOCK* completed_srb, unsigned scsi_sense) { completed_srb->SrbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID; completed_srb->ScsiStatus = SCSISTAT_CHECK_CONDITION; SenseData sense = default_sense; sense.sense_key = (scsi_sense >> 16) & 15; sense.asc = (scsi_sense >> 8) & 255; sense.ascq = scsi_sense & 255; unsigned sense_len = min(18U, completed_srb->SenseInfoBufferLength); if (sense_len > 0) { ScsiPortMoveMemory(completed_srb->SenseInfoBuffer, const_cast(&sense), sense_len); completed_srb->SenseInfoBufferLength = sense_len; } completed_srb->DataTransferLength = 0; Complete(completed_srb); } void DVDProxy::CompleteWithData(SCSI_REQUEST_BLOCK* Srb, const unsigned char* data, unsigned len, unsigned alloc) { unsigned transfer_length = min(len, alloc); if (transfer_length > Srb->DataTransferLength) transfer_length = Srb->DataTransferLength; ScsiPortMoveMemory(Srb->DataBuffer, (void*)data, transfer_length); Srb->DataTransferLength = transfer_length; CompleteWithScsiSuccess(Srb); } static inline void CopyCDB(void* dst, void* src) { ((unsigned*)dst)[0] = ((unsigned*)src)[0]; ((unsigned*)dst)[1] = ((unsigned*)src)[1]; ((unsigned*)dst)[2] = ((unsigned*)src)[2]; ((unsigned*)dst)[3] = ((unsigned*)src)[3]; }; bool DVDProxy::ConstructUserModeRequest(SCSI_REQUEST_BLOCK* src, ULONG sequence_number, SCSI_REQUEST_BLOCK* dst) { DBGPRINT((DBGLEVEL "sending request for %x(%d)\n", src, sequence_number)); if (dst->SenseInfoBuffer) { for (int i=0; iSenseInfoBufferLength; ++i) ((char*)dst->SenseInfoBuffer)[i] = i+0xAB; } unsigned data_bytes = (src->SrbFlags & SRB_FLAGS_DATA_OUT) ? src->DataTransferLength : 0; unsigned total_bytes = data_bytes + sizeof(UserModeRequest); if (total_bytes > dst->DataTransferLength) { // DBGPRINT((DBGLEVEL "DVDPROXY_ERROR_NEED_MORE_DATA_SPACE: had %d, need %d (cdb=%s)\n", dst->DataTransferLength, total_bytes, CDBString(src->Cdb, src->CdbLength))); return false; } UserModeRequest* req = (UserModeRequest*)dst->DataBuffer; req->sequence_number = sequence_number; req->target = src->TargetId; req->data_transfer_direction = UCHAR((src->SrbFlags >> 6) & 3); req->cdb_length = src->CdbLength; req->reserved = 0; req->data_transfer_length = src->DataTransferLength; CopyCDB(req->cdb, src->Cdb); UCHAR* data = (UCHAR*)req + sizeof(UserModeRequest); if (data_bytes) ScsiPortMoveMemory(data, src->DataBuffer, data_bytes); dst->DataTransferLength = total_bytes; dst->SenseInfoBufferLength = 0; return true; } void DVDProxy::UnpackUserModeResponse(SCSI_REQUEST_BLOCK* src, SCSI_REQUEST_BLOCK* dst) { CDB_RetireSRB* resp = (CDB_RetireSRB*)src->Cdb; dst->SrbStatus = resp->srb_status; dst->ScsiStatus = resp->scsi_status; dst->DataTransferLength = min(dst->DataTransferLength, src->DataTransferLength - 18*resp->sense_included); if (dst->DataTransferLength) ScsiPortMoveMemory(dst->DataBuffer, src->DataBuffer, dst->DataTransferLength); dst->SenseInfoBufferLength = min(dst->SenseInfoBufferLength, 18*resp->sense_included); if (dst->SenseInfoBufferLength) { SenseData* sense_data = (SenseData*)((char*)src->DataBuffer + src->DataTransferLength - 18); ScsiPortMoveMemory(dst->SenseInfoBuffer, sense_data, dst->SenseInfoBufferLength); } } VOID DVDProxy::ScsiTimer() { if (!user_attached) return; DBGPRINT((DBGLEVEL "listen=%d response=%d\n", user_listen_countdown, user_response_countdown)); if (srb_listen) { if (user_listen_countdown > 0) { --user_listen_countdown; } if (user_listen_countdown == 0) { CompleteWithScsiSense(srb_listen, DVDPROXY_ERROR_LISTEN_TIMEOUT); srb_listen = NULL; } } else { if (user_response_countdown > 0) { --user_response_countdown; } if (user_response_countdown == 0) { user_attached = false; ResetBus(0); } } ScsiPortNotification(RequestTimerCall, this, HwScsiTimer, tick_length); } void DVDProxy::HandleSkeletonDevice(SCSI_REQUEST_BLOCK* Srb) { InquiryData* data = &inquiry_data[Srb->TargetId-1]; if (data->inquiry_length == 0) { CompleteWithSrbStatus(Srb, SRB_STATUS_INVALID_TARGET_ID); } else if (Srb->Cdb[0] == SCSIOP_INQUIRY) { if (Srb->Cdb[1] == 0 && Srb->Cdb[2] == 0) { CompleteWithData(Srb, data->inquiry, data->inquiry_length, ScsiByteToInt(Srb->Cdb[4])); } else { CompleteWithScsiSense(Srb, 0x52400); // INVALID FIELD IN CDB } } else if (Srb->Cdb[0] == SCSIOP_MODE_SENSE10 && data->modepage_2a_length != 0) { if (Srb->Cdb[1] == 0 && Srb->Cdb[2] == 0x2A) { // Mode page 0x2A (CD/DVD Capabilities and Mechanical Status) CompleteWithData(Srb, data->modepage_2a, data->modepage_2a_length, Srb->Cdb[7]*256+Srb->Cdb[8]); } else { CompleteWithScsiSense(Srb, 0x52400); // INVALID FIELD IN CDB } } else { CompleteWithScsiSense(Srb, 0x52000); // INVALID COMMAND OPERATION CODE } } void DVDProxy::HandleDummyDevice(SCSI_REQUEST_BLOCK* Srb) { // I have to simulate this device because the idiot ScsiPort wrapper // won't pass SCSI commands to my driver unless I convince it there's // a device on the bus. if (Srb->Cdb[0] == SCSIOP_INQUIRY && Srb->Cdb[1] == 0 && Srb->Cdb[2] == 0) { CompleteWithData(Srb, dvdproxy_device_inquiry_data, 36, ScsiByteToInt(Srb->Cdb[4])); } else if (Srb->Cdb[0] == DVDPROXY_SCSIOP && Srb->Cdb[1] == DVDPROXY_VERSION) { switch (Srb->Cdb[2]) { case DVDPROXY_CMD_GET_SRB: // DBGPRINT((DBGLEVEL "DVDPROXY_CMD_GET_SRB\n")); if (srb_listen != NULL) { DBGPRINT((DBGLEVEL "Someone is already listening (this should never happen)\n")); CompleteWithScsiSense(srb_listen, DVDPROXY_ERROR_OLD_LISTENER); srb_listen = NULL; } { CDB_GetSRB* cdb = (CDB_GetSRB*)Srb->Cdb; tick_length = 1000 * cdb->tick_length_in_ms; user_listen_countdown = cdb->listen_timeout; user_response_countdown = cdb->response_timeout; if (!user_attached) { user_attached = true; ScsiPortNotification(RequestTimerCall, this, HwScsiTimer, tick_length); } ULONG seqnum; SCSI_REQUEST_BLOCK* dispatch_srb = queue.GetDispatchSRB(&seqnum); if (dispatch_srb) { DBGPRINT((DBGLEVEL "Dispatching %x\n", dispatch_srb)); if (ConstructUserModeRequest(dispatch_srb, seqnum, Srb)) { CompleteWithScsiSuccess(Srb); } else { DBGPRINT((DBGLEVEL "Dispatch failed: need more space\n", dispatch_srb)); queue.UngetDispatchSRB(); CompleteWithScsiSense(Srb, DVDPROXY_ERROR_NEED_MORE_DATA_SPACE); } } else { DBGPRINT((DBGLEVEL "Putting request on hold\n")); srb_listen = Srb; } } break; case DVDPROXY_CMD_KEEP_ALIVE: DBGPRINT((DBGLEVEL "DVDPROXY_CMD_KEEP_ALIVE\n")); user_response_countdown = ((CDB_KeepAlive*)Srb->Cdb)->ticks; if (!user_attached) { user_attached = true; ScsiPortNotification(RequestTimerCall, this, HwScsiTimer, tick_length); } break; case DVDPROXY_CMD_RETIRE_SRB: // DBGPRINT((DBGLEVEL "DVDPROXY_CMD_RETIRE_SRB\n")); { ULONG seqnum = ((CDB_RetireSRB*)Srb->Cdb)->sequence_number; SCSI_REQUEST_BLOCK* retire_srb = queue.RemoveRetireeByIndex(seqnum); if (retire_srb) { DBGPRINT((DBGLEVEL "Retiring %x\n", retire_srb)); UnpackUserModeResponse(Srb, retire_srb); Complete(retire_srb); } else { DBGPRINT((DBGLEVEL "Attemped to retire an unqueued SRB (%d)\n", seqnum)); } CompleteWithScsiSuccess(Srb); } break; case DVDPROXY_CMD_BUS_CHANGE: DBGPRINT((DBGLEVEL "DVDPROXY_CMD_BUS_CHANGE\n")); CompleteWithScsiSuccess(Srb); ScsiPortNotification(BusChangeDetected, this, 0); break; case DVDPROXY_CMD_SET_INQUIRY_DATA: DBGPRINT((DBGLEVEL "DVDPROXY_CMD_SET_INQUIRY_DATA\n")); ScsiPortMoveMemory(inquiry_data, Srb->DataBuffer, min(Srb->DataTransferLength, 31*sizeof(InquiryData))); CompleteWithScsiSuccess(Srb); break; case DVDPROXY_CMD_DETACH: DBGPRINT((DBGLEVEL "DVDPROXY_CMD_DETACH\n")); if (srb_listen) { CompleteWithScsiSense(srb_listen, DVDPROXY_ERROR_DETACH); } user_attached = false; CompleteWithScsiSuccess(Srb); break; case DVDPROXY_CMD_GENERATE_ERROR: DBGPRINT((DBGLEVEL "DVDPROXY_CMD_GENERATE_ERROR\n")); CompleteWithSrbStatus(Srb, ((CDB_GenerateError*)Srb->Cdb)->error_code); break; default: DBGPRINT((DBGLEVEL "invalid operation code (%d)\n", Srb->Cdb[2])); CompleteWithScsiSense(Srb, DVDPROXY_ERROR_INVALID_COMMAND); break; } } else { CompleteWithScsiSense(Srb, 0x52000); // INVALID COMMAND OPERATION CODE } } void DVDProxy::QueueSRB(SCSI_REQUEST_BLOCK* Srb) { DBGPRINT((DBGLEVEL "Queueing %x\n", Srb)); if (!queue.AddIncomingSRB(Srb)) { DBGPRINT((DBGLEVEL "Queue full!\n")); CompleteWithSrbStatus(Srb, SRB_STATUS_BUSY); return; } if (srb_listen) { ULONG seqnum; SCSI_REQUEST_BLOCK* dispatch_srb = queue.GetDispatchSRB(&seqnum); // assert(dispatch_srb == Srb); if (dispatch_srb) { DBGPRINT((DBGLEVEL "Dispatching %x immediately\n", dispatch_srb)); if (ConstructUserModeRequest(dispatch_srb, seqnum, srb_listen)) { CompleteWithScsiSuccess(srb_listen); } else { DBGPRINT((DBGLEVEL "Dispatch failed: need more space\n", dispatch_srb)); queue.UngetDispatchSRB(); CompleteWithScsiSense(srb_listen, DVDPROXY_ERROR_NEED_MORE_DATA_SPACE); } srb_listen = NULL; } else { DBGPRINT((DBGLEVEL "No SRB to dispatch! (bug)\n", Srb)); } } else { DBGPRINT((DBGLEVEL "No current listener\n", Srb)); } } BOOLEAN DVDProxy::StartIo(SCSI_REQUEST_BLOCK* Srb) { #ifdef DBGLEVEL queue.DebugPrintQueue(); #endif unsigned char path = Srb->PathId, targ = Srb->TargetId, lun = Srb->Lun; switch (Srb->Function) { case SRB_FUNCTION_EXECUTE_SCSI: DBGPRINT((DBGLEVEL "SCSI command: Srb=%x Addr=%d:%d:%d Data=%d Cdb=%s\n", Srb, path, targ, lun, Srb->DataTransferLength, CDBString(Srb->Cdb, Srb->CdbLength))); ZeroMemory(Srb->SenseInfoBuffer, Srb->SenseInfoBufferLength); if (path != 0) { DBGPRINT((DBGLEVEL "pathid != 0\n")); CompleteWithSrbStatus(Srb, SRB_STATUS_INVALID_PATH_ID); } else if (lun != 0) { DBGPRINT((DBGLEVEL "lun != 0\n")); CompleteWithSrbStatus(Srb, SRB_STATUS_INVALID_LUN); } else if (targ == 0) { HandleDummyDevice(Srb); } else if (user_attached) { QueueSRB(Srb); } else { HandleSkeletonDevice(Srb); } break; case SRB_FUNCTION_IO_CONTROL: case SRB_FUNCTION_ABORT_COMMAND: case SRB_FUNCTION_TERMINATE_IO: DBGPRINT((DBGLEVEL "SRB_FUNCTION_ABORT_COMMAND or SRB_FUNCTION_TERMINATE_IO\n")); queue.RemoveSRB(Srb->NextSrb); CompleteWithSrbStatus(Srb->NextSrb, SRB_STATUS_ABORTED); CompleteWithSrbStatus(Srb, SRB_STATUS_SUCCESS); break; case SRB_FUNCTION_RESET_BUS: DBGPRINT((DBGLEVEL "SRB_FUNCTION_RESET_BUS\n")); ResetBus(path); CompleteWithSrbStatus(Srb, SRB_STATUS_SUCCESS); break; /* #ifdef DBGLEVEL case SRB_FUNCTION_IO_CONTROL: { struct SRB_IO_CONTROL { ULONG hdrlen; UCHAR sig[8]; ULONG timeout; ULONG ctlcode; ULONG rtncode; ULONG len; }; SRB_IO_CONTROL* ioctl = (SRB_IO_CONTROL*)Srb->DataBuffer; ioctl->timeout = 0; DBGPRINT((DBGLEVEL "SRB_FUNCTION_IO_CONTROL: %s %x len=%d\n", ioctl->sig, ioctl->ctlcode, ioctl->len)); CompleteWithSrbStatus(Srb, SRB_STATUS_INVALID_REQUEST); break; } #endif */ default: DBGPRINT((DBGLEVEL "Srb->Function=%d\n", Srb->Function)); CompleteWithSrbStatus(Srb, SRB_STATUS_INVALID_REQUEST); break; } // ScsiPortNotification(NextLuRequest, this, path, targ, lun); ScsiPortNotification(NextRequest, this, NULL); return TRUE; } extern "C" ULONG DriverEntry(IN PVOID DriverObject, IN PVOID Argument2) { DBGPRINT((DBGLEVEL "DVDProxy DriverEntry\n")); HW_INITIALIZATION_DATA hwInitializationData; ZeroMemory(&hwInitializationData, sizeof(hwInitializationData)); hwInitializationData.HwInitializationDataSize = 80;/*sizeof(hwInitializationData)*/ hwInitializationData.AdapterInterfaceType = Isa; hwInitializationData.HwInitialize = HwInitialize; hwInitializationData.HwStartIo = HwStartIo; hwInitializationData.HwFindAdapter = HwFindAdapter; hwInitializationData.HwResetBus = HwResetBus; hwInitializationData.DeviceExtensionSize = sizeof(DVDProxy); // hwInitializationData.NumberOfAccessRanges = 1; hwInitializationData.MapBuffers = TRUE; hwInitializationData.AutoRequestSense = TRUE; // hwInitializationData.MultipleRequestPerLu = TRUE; // hwInitializationData.TaggedQueuing = TRUE; hwInitializationData.HwAdapterControl = HwAdapterControl; return ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, 0); }