NTSTATUS ScsiPortPdoScsi( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) /*++ Routine Description: This routine dispatches SRB's for a particular target device. It will fill in the Port, Path, Target and Lun values and then forward the request through to the FDO for the bus Arguments: Pdo - a pointer to the physical device object Irp - a pointer to the io request packet Return Value: status --*/ { PLOGICAL_UNIT_EXTENSION lun = Pdo->DeviceExtension; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); #if DBG PDRIVER_OBJECT lowerDriverObject = lun->CommonExtension.LowerDeviceObject->DriverObject; #endif PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb; ULONG isRemoved; PSRB_DATA srbData; BOOLEAN isLock = FALSE; NTSTATUS status; isRemoved = SpAcquireRemoveLock(Pdo, Irp); if(isRemoved && !IS_CLEANUP_REQUEST(irpStack) && (srb->Function != SRB_FUNCTION_CLAIM_DEVICE)) { Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; SpReleaseRemoveLock(Pdo, Irp); SpCompleteRequest(Pdo, Irp, NULL, IO_NO_INCREMENT); return STATUS_DEVICE_DOES_NOT_EXIST; } srb->PathId = lun->PathId; srb->TargetId = lun->TargetId; srb->Lun = lun->Lun; // // NOTICE: The SCSI-II specification indicates that this field should be // zero; however, some target controllers ignore the logical unit number // in the INDENTIFY message and only look at the logical unit number field // in the CDB. // srb->Cdb[1] |= srb->Lun << 5; // // Queue tags should be assigned only by the StartIo routine. Set it to // a benign value here so we can tell later on that we don't have to // clear the tag value in the bitmap. // srb->QueueTag = SP_UNTAGGED; #if DBG ASSERT(lowerDriverObject->MajorFunction[IRP_MJ_SCSI] != NULL); ASSERT(lowerDriverObject->MajorFunction[IRP_MJ_SCSI] == ScsiPortGlobalDispatch); #endif switch(srb->Function) { case SRB_FUNCTION_ABORT_COMMAND: { // // BUGBUG - abort is broken. We'll need to either yank it out // or figure out how to recode it internally. Abort commands // are going to need their own SRB_DATA structure since that // contains the pointer back to the original irp. // ASSERT(FALSE); status = STATUS_NOT_SUPPORTED; break; } case SRB_FUNCTION_CLAIM_DEVICE: case SRB_FUNCTION_REMOVE_DEVICE: { status = SpClaimLogicalUnit( lun->CommonExtension.LowerDeviceObject->DeviceExtension, lun, Irp, FALSE); break; } case SRB_FUNCTION_UNLOCK_QUEUE: case SRB_FUNCTION_LOCK_QUEUE: { BOOLEAN lock; lock = (srb->Function == SRB_FUNCTION_LOCK_QUEUE); // // This srb function is only valid as part of a power up request // and will be ignored if the power state is D0. // DebugPrint((2, "ScsiPortPdoScsi: called to %s queue %#p\n", lock ? "lock" : "unlock", lun)); ASSERT(lun->LockRequest == NULL); CLEAR_FLAG(srb->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE); SET_FLAG(srb->SrbFlags, SRB_FLAGS_BYPASS_LOCKED_QUEUE); isLock = TRUE; // // Throw this request down so it gets processed as a real // request. We need to get the completion dpc to start // things running again. there are too many flags to set // to do it from here. // DebugPrint((2, "ScsiPortPdoScsi: %s %#p into " "queue %#p ... issuing request\n", lock ? "lock" : "unlock", srb, lun)); srbData = SpAllocateBypassSrbData(lun); ASSERT(srbData != NULL); goto RunSrb; } case SRB_FUNCTION_RELEASE_QUEUE: case SRB_FUNCTION_FLUSH_QUEUE: { srbData = SpAllocateBypassSrbData(lun); ASSERT(srbData != NULL); goto RunSrb; } default: { if(TEST_FLAG(srb->SrbFlags, (SRB_FLAGS_BYPASS_LOCKED_QUEUE | SRB_FLAGS_BYPASS_FROZEN_QUEUE))) { srbData = SpAllocateBypassSrbData(lun); ASSERT(srbData != NULL); } else { srbData = SpAllocateSrbData( lun->AdapterExtension, Irp); if(srbData == NULL) { // // There wasn't an SRB_DATA block available for this // request so it's been queued waiting for resources - // leave the logical unit remove-locked and return pending. // DebugPrint((1, "ScsiPortPdoScsi: Insufficient resources " "to allocate SRB_DATA structure\n")); return STATUS_PENDING; } } RunSrb: srbData->CurrentIrp = Irp; srbData->CurrentSrb = srb; srbData->LogicalUnit = lun; srb->OriginalRequest = srbData; return SpDispatchRequest(lun, Irp); } } Irp->IoStatus.Status = status; SpReleaseRemoveLock(Pdo, Irp); SpCompleteRequest(Pdo, Irp, NULL, IO_NO_INCREMENT); return status; }
NTSTATUS NTAPI ClassCreateClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: SCSI class driver create and close routine. This is called by the I/O system when the device is opened or closed. Arguments: DriverObject - Pointer to driver object created by system. Irp - IRP involved. Return Value: Device-specific drivers return value or STATUS_SUCCESS. --*/ { PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; ULONG removeState; NTSTATUS status; PAGED_CODE(); // // If we're getting a close request then we know the device object hasn't // been completely destroyed. Let the driver cleanup if necessary. // removeState = ClassAcquireRemoveLock(DeviceObject, Irp); // // Invoke the device-specific routine, if one exists. Otherwise complete // with SUCCESS // if((removeState == NO_REMOVE) || IS_CLEANUP_REQUEST(IoGetCurrentIrpStackLocation(Irp)->MajorFunction)) { status = ClasspCreateClose(DeviceObject, Irp); if((NT_SUCCESS(status)) && (commonExtension->DevInfo->ClassCreateClose)) { return commonExtension->DevInfo->ClassCreateClose(DeviceObject, Irp); } } else { status = STATUS_DEVICE_DOES_NOT_EXIST; } Irp->IoStatus.Status = status; ClassReleaseRemoveLock(DeviceObject, Irp); ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); return status; }