BOOLEAN MpHwStartIo( __in pHW_HBA_EXT pHBAExt, // Adapter device-object extension from port driver. __in __out PSCSI_REQUEST_BLOCK pSrb ) { UCHAR Result = ResultDone; #ifdef USE_SCSIPORT UCHAR PathId = pSrb->PathId; UCHAR TargetId = pSrb->TargetId; UCHAR Lun = pSrb->Lun; #endif KdPrint2(("PhDskMnt::MpHwStartIo: pHBAExt = 0x%p, pSrb = 0x%p, Path=%i, Target=%i, Lun=%i, IRQL=%i\n", pHBAExt, pSrb, (int) pSrb->PathId, (int) pSrb->TargetId, (int) pSrb->Lun, KeGetCurrentIrql())); pSrb->SrbStatus = SRB_STATUS_PENDING; pSrb->ScsiStatus = SCSISTAT_GOOD; ImScsiCompletePendingSrbs(pHBAExt); _InterlockedExchangeAdd((volatile LONG *)&pHBAExt->SRBsSeen, 1); // Bump count of SRBs encountered. // Next, if true, will cause port driver to remove the associated LUNs if, for example, devmgmt.msc is asked "scan for hardware changes." //if (pHBAExt->bDontReport) //{ // Act as though the HBA/path is gone? // pSrb->SrbStatus = SRB_STATUS_INVALID_LUN; // goto done; //} switch (pSrb->Function) { case SRB_FUNCTION_IO_CONTROL: ScsiIoControl(pHBAExt, pSrb, &Result); break; case SRB_FUNCTION_EXECUTE_SCSI: ScsiExecute(pHBAExt, pSrb, &Result); break; case SRB_FUNCTION_RESET_LOGICAL_UNIT: DbgPrint("PhDskMnt::MpHwStartIo: SRB_FUNCTION_RESET_LOGICAL_UNIT.\n"); pSrb->SrbStatus = ScsiResetLun(pHBAExt, pSrb); break; case SRB_FUNCTION_RESET_DEVICE: DbgPrint("PhDskMnt::MpHwStartIo: SRB_FUNCTION_RESET_DEVICE.\n"); pSrb->SrbStatus = ScsiResetDevice(pHBAExt, pSrb); break; case SRB_FUNCTION_RESET_BUS: DbgPrint("PhDskMnt::MpHwStartIo: SRB_FUNCTION_RESET_BUS.\n"); pSrb->SrbStatus = MpHwResetBus(pHBAExt, pSrb->PathId); break; case SRB_FUNCTION_PNP: MpHwHandlePnP(pHBAExt, (PSCSI_PNP_REQUEST_BLOCK)pSrb); break; case SRB_FUNCTION_POWER: KdPrint(("PhDskMnt::MpHwStartIo: SRB_FUNCTION_POWER.\n")); // Do nothing. pSrb->SrbStatus = SRB_STATUS_SUCCESS; break; case SRB_FUNCTION_SHUTDOWN: KdPrint(("PhDskMnt::MpHwStartIo: SRB_FUNCTION_SHUTDOWN.\n")); // Do nothing. pSrb->SrbStatus = SRB_STATUS_SUCCESS; break; default: KdPrint(("PhDskMnt::MpHwStartIo: Unknown pSrb Function = 0x%x\n", pSrb->Function)); ScsiSetCheckCondition(pSrb, SRB_STATUS_ERROR, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ADSENSE_ILLEGAL_COMMAND, 0); break; } // switch (pSrb->Function) if (Result == ResultDone) { // Complete now? // Note: A miniport with real hardware would not always be calling RequestComplete from HwScsiStartIo. Rather, // the miniport would typically be doing real I/O and would call RequestComplete only at the end of that // real I/O, in its HwScsiInterrupt or in a DPC routine. #ifdef USE_SCSIPORT KdPrint2(("PhDskMnt::MpHwStartIo sending 'RequestComplete', 'NextRequest' and 'NextLuRequest' to ScsiPort.\n")); ScsiPortNotification(RequestComplete, pHBAExt, pSrb); ScsiPortNotification(NextRequest, pHBAExt); ScsiPortNotification(NextLuRequest, pHBAExt, 0, 0, 0); #endif #ifdef USE_STORPORT KdPrint2(("PhDskMnt::MpHwStartIo sending 'RequestComplete' to port StorPort.\n")); StorPortNotification(RequestComplete, pHBAExt, pSrb); #endif } else { #ifdef USE_SCSIPORT _InterlockedExchangeAdd((volatile LONG*)&pHBAExt->WorkItems, 1); KdPrint2(("PhDskMnt::MpHwStartIo sending 'RequestTimerCall' and 'NextLuRequest' to ScsiPort.\n")); ScsiPortNotification(RequestTimerCall, pHBAExt, MpHwTimer, (ULONG) 1); ScsiPortNotification(NextLuRequest, pHBAExt, PathId, TargetId, Lun); ScsiPortNotification(NextLuRequest, pHBAExt, 0, 0, 0); #endif } KdPrint2(("PhDskMnt::MpHwStartIo End.\n")); return TRUE; } // End MpHwStartIo().
VOID ImScsiExtendDevice( __in pHW_HBA_EXT pHBAExt, __in PSCSI_REQUEST_BLOCK pSrb, __inout __deref PUCHAR pResult, __inout __deref PKIRQL LowestAssumedIrql, __inout __deref PSRB_IMSCSI_EXTEND_DEVICE extend_device_data ) { UCHAR scsi_status; pHW_LU_EXTENSION device_extension; KdPrint(("ImScsi: Request to grow device %i:%i:%i by %I64i bytes.\n", (int)extend_device_data->DeviceNumber.PathId, (int)extend_device_data->DeviceNumber.TargetId, (int)extend_device_data->DeviceNumber.Lun, extend_device_data->ExtendSize.QuadPart)); scsi_status = ScsiGetLUExtension( pHBAExt, &device_extension, extend_device_data->DeviceNumber.PathId, extend_device_data->DeviceNumber.TargetId, extend_device_data->DeviceNumber.Lun, LowestAssumedIrql ); if ((scsi_status != SRB_STATUS_SUCCESS) | (device_extension == NULL)) { extend_device_data->SrbIoControl.ReturnCode = (ULONG)STATUS_OBJECT_NAME_NOT_FOUND; ScsiSetSuccess(pSrb, pSrb->DataTransferLength); return; } if (device_extension->ReadOnly) { extend_device_data->SrbIoControl.ReturnCode = (ULONG)STATUS_MEDIA_WRITE_PROTECTED; ScsiSetSuccess(pSrb, pSrb->DataTransferLength); return; } pMP_WorkRtnParms pWkRtnParms = // Allocate parm area for work routine. (pMP_WorkRtnParms)ExAllocatePoolWithTag(NonPagedPool, sizeof(MP_WorkRtnParms), MP_TAG_GENERAL); if (pWkRtnParms == NULL) { DbgPrint("ImScsi::ImScsiExtendDevice Failed to allocate work parm structure\n"); ScsiSetCheckCondition(pSrb, SRB_STATUS_ERROR, SCSI_SENSE_HARDWARE_ERROR, SCSI_ADSENSE_NO_SENSE, 0); return; } RtlZeroMemory(pWkRtnParms, sizeof(MP_WorkRtnParms)); pWkRtnParms->pHBAExt = pHBAExt; pWkRtnParms->pLUExt = device_extension; pWkRtnParms->pSrb = pSrb; KEVENT wait_event; BOOLEAN wait_result = KeGetCurrentIrql() < DISPATCH_LEVEL; if (wait_result) { KeInitializeEvent(&wait_event, EVENT_TYPE::NotificationEvent, FALSE); pWkRtnParms->CallerWaitEvent = &wait_event; } // Queue work item, which will run in the System process. KLOCK_QUEUE_HANDLE lock_handle; KdPrint2(("PhDskMnt::ImScsiExtendDevice: Queuing work=0x%p\n", pWkRtnParms)); ImScsiAcquireLock(&device_extension->RequestListLock, &lock_handle, *LowestAssumedIrql); InsertTailList(&device_extension->RequestList, &pWkRtnParms->RequestListEntry); ImScsiReleaseLock(&lock_handle, LowestAssumedIrql); KeSetEvent(&device_extension->RequestEvent, (KPRIORITY)0, FALSE); *pResult = ResultQueued; // Indicate queuing. if (wait_result) { KeWaitForSingleObject(&wait_event, KWAIT_REASON::Executive, MODE::KernelMode, FALSE, NULL); } StoragePortNotification(BusChangeDetected, pHBAExt, extend_device_data->DeviceNumber.PathId); return; }
BOOLEAN MpHwStartIo( __in PVOID DeviceExtension, // Adapter device-object extension from port driver. __inout __deref PSCSI_REQUEST_BLOCK pSrb ) { KIRQL lowest_assumed_irql = PASSIVE_LEVEL; ResultType Result = ResultDone; pHW_HBA_EXT pHBAExt = (pHW_HBA_EXT)DeviceExtension; #ifdef USE_SCSIPORT UCHAR PathId = pSrb->PathId; UCHAR TargetId = pSrb->TargetId; UCHAR Lun = pSrb->Lun; #endif KdPrint2(("PhDskMnt::MpHwStartIo: pHBAExt = 0x%p, pSrb = 0x%p, Path=%i, Target=%i, Lun=%i, IRQL=%i\n", pHBAExt, pSrb, (int)pSrb->PathId, (int)pSrb->TargetId, (int)pSrb->Lun, KeGetCurrentIrql())); pSrb->SrbStatus = SRB_STATUS_PENDING; pSrb->ScsiStatus = SCSISTAT_GOOD; ImScsiCompletePendingSrbs(pHBAExt, &lowest_assumed_irql); _InterlockedExchangeAdd((volatile LONG *)&pHBAExt->SRBsSeen, 1); // Bump count of SRBs encountered. // Next, if true, will cause port driver to remove the associated LUNs if, for example, devmgmt.msc is asked "scan for hardware changes." //if (pHBAExt->bDontReport) //{ // Act as though the HBA/path is gone? // pSrb->SrbStatus = SRB_STATUS_NO_DEVICE; // goto done; //} switch (pSrb->Function) { case SRB_FUNCTION_IO_CONTROL: ScsiIoControl(pHBAExt, pSrb, &Result, &lowest_assumed_irql); break; case SRB_FUNCTION_EXECUTE_SCSI: if (pSrb->Cdb[0] == SCSIOP_REPORT_LUNS) { ScsiOpReportLuns(pHBAExt, pSrb, &lowest_assumed_irql); } else { ScsiExecute(pHBAExt, pSrb, &Result, &lowest_assumed_irql); } break; case SRB_FUNCTION_RESET_LOGICAL_UNIT: DbgPrint("PhDskMnt::MpHwStartIo: SRB_FUNCTION_RESET_LOGICAL_UNIT.\n"); pSrb->SrbStatus = ScsiResetLun(pHBAExt, pSrb); break; case SRB_FUNCTION_RESET_DEVICE: DbgPrint("PhDskMnt::MpHwStartIo: SRB_FUNCTION_RESET_DEVICE.\n"); pSrb->SrbStatus = ScsiResetDevice(pHBAExt, pSrb); break; case SRB_FUNCTION_RESET_BUS: DbgPrint("PhDskMnt::MpHwStartIo: SRB_FUNCTION_RESET_BUS.\n"); pSrb->SrbStatus = MpHwResetBus(pHBAExt, pSrb->PathId); break; case SRB_FUNCTION_PNP: ScsiPnP(pHBAExt, (PSCSI_PNP_REQUEST_BLOCK)pSrb, &lowest_assumed_irql); break; case SRB_FUNCTION_POWER: KdPrint(("PhDskMnt::MpHwStartIo: SRB_FUNCTION_POWER.\n")); // Do nothing. pSrb->SrbStatus = SRB_STATUS_SUCCESS; break; case SRB_FUNCTION_SHUTDOWN: KdPrint(("PhDskMnt::MpHwStartIo: SRB_FUNCTION_SHUTDOWN.\n")); // Do nothing. pSrb->SrbStatus = SRB_STATUS_SUCCESS; break; default: KdPrint(("PhDskMnt::MpHwStartIo: Unknown pSrb Function = 0x%X\n", pSrb->Function)); //StorPortLogError(pHBAExt, pSrb, pSrb->PathId, pSrb->TargetId, pSrb->Lun, SP_PROTOCOL_ERROR, 0x0200 | pSrb->Cdb[0]); ScsiSetCheckCondition(pSrb, SRB_STATUS_ERROR, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ADSENSE_ILLEGAL_COMMAND, 0); break; } // switch (pSrb->Function) if (Result == ResultDone) { // Complete now? #ifdef USE_SCSIPORT KdPrint2(("PhDskMnt::MpHwStartIo sending 'RequestComplete', 'NextRequest' and 'NextLuRequest' to ScsiPort.\n")); ScsiPortNotification(RequestComplete, pHBAExt, pSrb); ScsiPortNotification(NextRequest, pHBAExt); ScsiPortNotification(NextLuRequest, pHBAExt, 0, 0, 0); #endif #ifdef USE_STORPORT KdPrint2(("PhDskMnt::MpHwStartIo sending 'RequestComplete' to port StorPort.\n")); StorPortNotification(RequestComplete, pHBAExt, pSrb); #endif } else { #ifdef USE_SCSIPORT _InterlockedExchangeAdd((volatile LONG*)&pHBAExt->WorkItems, 1); KdPrint2(("PhDskMnt::MpHwStartIo sending 'RequestTimerCall' and 'NextLuRequest' to ScsiPort.\n")); ScsiPortNotification(RequestTimerCall, pHBAExt, MpHwTimer, (ULONG)1); ScsiPortNotification(NextLuRequest, pHBAExt, PathId, TargetId, Lun); ScsiPortNotification(NextLuRequest, pHBAExt, 0, 0, 0); #endif } KdPrint2(("PhDskMnt::MpHwStartIo End.\n")); return TRUE; } // End MpHwStartIo().
VOID ImScsiDispatchWork( __in pMP_WorkRtnParms pWkRtnParms ) { pHW_HBA_EXT pHBAExt = pWkRtnParms->pHBAExt; pHW_LU_EXTENSION pLUExt = pWkRtnParms->pLUExt; PSCSI_REQUEST_BLOCK pSrb = pWkRtnParms->pSrb; PETHREAD pReqThread = pWkRtnParms->pReqThread; PCDB pCdb = (PCDB)pSrb->Cdb; KdPrint2(("PhDskMnt::ImScsiDispatchWork Action: 0x%X, pSrb: 0x%p, pSrb->DataBuffer: 0x%p pSrb->DataTransferLength: 0x%X\n", (int)pSrb->Cdb[0], pSrb, pSrb->DataBuffer, pSrb->DataTransferLength)); switch (pSrb->Function) { case SRB_FUNCTION_IO_CONTROL: { PSRB_IO_CONTROL srb_io_control = (PSRB_IO_CONTROL)pSrb->DataBuffer; switch (srb_io_control->ControlCode) { case SMP_IMSCSI_CREATE_DEVICE: { // Create new? KIRQL lowest_assumed_irql = PASSIVE_LEVEL; KdPrint(("PhDskMnt::ImScsiDispatchWork: Request to create new device.\n")); ImScsiCreateLU(pHBAExt, pSrb, pReqThread, &lowest_assumed_irql); ObDereferenceObject(pReqThread); } break; default: break; } } break; case SRB_FUNCTION_EXECUTE_SCSI: switch (pSrb->Cdb[0]) { case SCSIOP_READ: case SCSIOP_WRITE: case SCSIOP_READ16: case SCSIOP_WRITE16: { // Read/write? PVOID sysaddress; PVOID buffer; ULONG status; LARGE_INTEGER startingSector; LARGE_INTEGER startingOffset; KLOCK_QUEUE_HANDLE LockHandle; KIRQL lowest_assumed_irql = PASSIVE_LEVEL; if ((pCdb->AsByte[0] == SCSIOP_READ16) | (pCdb->AsByte[0] == SCSIOP_WRITE16)) { REVERSE_BYTES_QUAD(&startingSector, pCdb->CDB16.LogicalBlock); } else { startingSector.QuadPart = 0; REVERSE_BYTES(&startingSector, &pCdb->CDB10.LogicalBlockByte0); } startingOffset.QuadPart = startingSector.QuadPart << pLUExt->BlockPower; KdPrint2(("PhDskMnt::ImScsiDispatchWork starting sector: 0x%I64X\n", startingSector)); status = StoragePortGetSystemAddress(pHBAExt, pSrb, &sysaddress); if ((status != STORAGE_STATUS_SUCCESS) | (sysaddress == NULL)) { DbgPrint("PhDskMnt::ImScsiDispatchWork: StorPortGetSystemAddress failed: status=0x%X address=0x%p translated=0x%p\n", status, pSrb->DataBuffer, sysaddress); pSrb->SrbStatus = SRB_STATUS_ERROR; pSrb->ScsiStatus = SCSISTAT_GOOD; break; } buffer = ExAllocatePoolWithTag(NonPagedPool, pSrb->DataTransferLength, MP_TAG_GENERAL); if (buffer == NULL) { DbgPrint("PhDskMnt::ImScsiDispatchWork: Memory allocation failed.\n"); pSrb->SrbStatus = SRB_STATUS_ERROR; pSrb->ScsiStatus = SCSISTAT_GOOD; break; } else { NTSTATUS status = STATUS_NOT_IMPLEMENTED; /// For write operations, prepare temporary buffer if ((pSrb->Cdb[0] == SCSIOP_WRITE) | (pSrb->Cdb[0] == SCSIOP_WRITE16)) { RtlMoveMemory(buffer, sysaddress, pSrb->DataTransferLength); } if ((pSrb->Cdb[0] == SCSIOP_READ) | (pSrb->Cdb[0] == SCSIOP_READ16)) { status = ImScsiReadDevice(pLUExt, buffer, &startingOffset, &pSrb->DataTransferLength); } else if ((pSrb->Cdb[0] == SCSIOP_WRITE) | (pSrb->Cdb[0] == SCSIOP_WRITE16)) { status = ImScsiWriteDevice(pLUExt, buffer, &startingOffset, &pSrb->DataTransferLength); } if (!NT_SUCCESS(status)) { ExFreePoolWithTag(buffer, MP_TAG_GENERAL); DbgPrint("PhDskMnt::ImScsiDispatchWork: I/O error status=0x%X\n", status); switch (status) { case STATUS_INVALID_BUFFER_SIZE: { DbgPrint("PhDskMnt::ImScsiDispatchWork: STATUS_INVALID_BUFFER_SIZE from image I/O. Reporting SCSI_SENSE_ILLEGAL_REQUEST/SCSI_ADSENSE_INVALID_CDB/0x00.\n"); ScsiSetCheckCondition( pSrb, SRB_STATUS_ERROR, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ADSENSE_INVALID_CDB, 0); break; } case STATUS_DEVICE_BUSY: { DbgPrint("PhDskMnt::ImScsiDispatchWork: STATUS_DEVICE_BUSY from image I/O. Reporting SRB_STATUS_BUSY/SCSI_SENSE_NOT_READY/SCSI_ADSENSE_LUN_NOT_READY/SCSI_SENSEQ_BECOMING_READY.\n"); ScsiSetCheckCondition( pSrb, SRB_STATUS_BUSY, SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_BECOMING_READY ); break; } default: { ScsiSetError(pSrb, SRB_STATUS_PARITY_ERROR); break; } } break; } /// Fake random disk signature in case mounted read-only, 0xAA55 at end of mbr and 0x00000000 in disk id field. /// Compatibility fix for mounting Windows Backup vhd files in read-only. if ((pLUExt->FakeDiskSignature != 0) && ((pSrb->Cdb[0] == SCSIOP_READ) | (pSrb->Cdb[0] == SCSIOP_READ16)) && (startingSector.QuadPart == 0) && (pSrb->DataTransferLength >= 512) && (pLUExt->ReadOnly)) { PUCHAR mbr = (PUCHAR)buffer; if ((*(PUSHORT)(mbr + 0x01FE) == 0xAA55) & (*(PUSHORT)(mbr + 0x01BC) == 0x0000) & ((*(mbr + 0x01BE) & 0x7F) == 0x00) & ((*(mbr + 0x01CE) & 0x7F) == 0x00) & ((*(mbr + 0x01DE) & 0x7F) == 0x00) & ((*(mbr + 0x01EE) & 0x7F) == 0x00) & ((*(PULONG)(mbr + 0x01B8) == 0x00000000UL))) { DbgPrint("PhDskMnt::ImScsiDispatchWork: Faking disk signature as %#X.\n", pLUExt->FakeDiskSignature); *(PULONG)(mbr + 0x01B8) = pLUExt->FakeDiskSignature; } } /// For write operations, temporary buffer holds read data. /// Copy that to system buffer. if ((pSrb->Cdb[0] == SCSIOP_READ) | (pSrb->Cdb[0] == SCSIOP_READ16)) { RtlMoveMemory(sysaddress, buffer, pSrb->DataTransferLength); } } ImScsiAcquireLock(&pLUExt->LastIoLock, &LockHandle, lowest_assumed_irql); if (pLUExt->LastIoBuffer != NULL) ExFreePoolWithTag(pLUExt->LastIoBuffer, MP_TAG_GENERAL); pLUExt->LastIoStartSector = startingSector.QuadPart; pLUExt->LastIoLength = pSrb->DataTransferLength; pLUExt->LastIoBuffer = buffer; ImScsiReleaseLock(&LockHandle, &lowest_assumed_irql); ScsiSetSuccess(pSrb, pSrb->DataTransferLength); } break; default: { DbgPrint("PhDskMnt::ImScsiDispatchWork unknown function: 0x%X\n", (int)pSrb->Cdb[0]); ScsiSetError(pSrb, SRB_STATUS_INTERNAL_ERROR); } } default: break; } KdPrint2(("PhDskMnt::ImScsiDispatchWork: End pSrb: 0x%p.\n", pSrb)); } // End ImScsiDispatchWork().