void com_apple_dts_SCSIEmulatorAdapter::CompleteTaskOnWorkloopThread ( SCSIParallelTaskIdentifier parallelRequest, bool transportSuccessful, SCSITaskStatus scsiStatus, UInt64 actuallyTransferred, UInt8* senseBuffer, int senseLength) { // SCSITargetIdentifier target = GetTargetIdentifier(parallelRequest); UInt8 transferDir = GetDataTransferDirection(parallelRequest); UInt64 transferSizeMax = GetRequestedDataTransferCount(parallelRequest); // IOMemoryDescriptor * transferMemDesc = GetDataBuffer(parallelRequest); SCSIEmulatorRequestBlock * srb = ( SCSIEmulatorRequestBlock * ) GetHBADataPointer ( parallelRequest ); if (transportSuccessful && (scsiStatus != kSCSITaskStatus_TASK_SET_FULL)) { // set the realized transfer counts switch (transferDir) { case kSCSIDataTransfer_FromTargetToInitiator: { if (actuallyTransferred > transferSizeMax) { actuallyTransferred = transferSizeMax; } if (!SetRealizedDataTransferCount(parallelRequest, actuallyTransferred)) { IOLog("CompleteTaskOnWorkloopThread: SetRealizedDataTransferCount (%d bytes) returned FAIL\n", actuallyTransferred); } break; } case kSCSIDataTransfer_FromInitiatorToTarget: { if (actuallyTransferred > transferSizeMax) { actuallyTransferred = transferSizeMax; } if (!SetRealizedDataTransferCount(parallelRequest, actuallyTransferred)) { IOLog("CompleteTaskOnWorkloopThread: SetRealizedDataTransferCount (%d bytes) returned FAIL\n", actuallyTransferred); } break; } case kSCSIDataTransfer_NoDataTransfer: default: { break; } } } // Now, add the completion to the queue to be checked by the workloop thread. The completion needs // to be done on the workloop to allow the stack to unwind itself or you risk running into a panic. // The addItemToQueue method in the event source signals the workloop to check the queue after the task // is added. if (!transportSuccessful) { IOLog("CompleteTaskOnWorkloopThread: Failed transport - task = %p, transferDir = %d, transferSize = %lld, scsiStatus = 0x%X\n", parallelRequest, transferDir, transferSizeMax, scsiStatus); queue_init(&srb->fQueueChain); srb->fTask = parallelRequest; srb->fTaskStatus = scsiStatus; srb->fServiceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; mResponderEventSource->addItemToQueue(srb); } else { // handle sense data in common fashion and complete the task if (senseLength > 0) { if (!SetAutoSenseData(parallelRequest, (SCSI_Sense_Data*) senseBuffer, senseLength)) { IOLog("CompleteTaskOnWorkloopThread: Could not set sense data in parallel task\n"); } } queue_init(&srb->fQueueChain); srb->fTask = parallelRequest; srb->fTaskStatus = scsiStatus; srb->fServiceResponse = kSCSIServiceResponse_TASK_COMPLETE; mResponderEventSource->addItemToQueue(srb); } }
bool com_ximeta_driver_NDASProtocolTransport::SendSCSICommand ( SCSITaskIdentifier request, SCSIServiceResponse * serviceResponse, SCSITaskStatus * taskStatus ) { UInt8 commandLength = 0; bool commandProcessed = true; com_ximeta_driver_NDASSCSICommand *NDCmd_ptr = NULL; SCSICommand scsiCommand; DbgIOLog(DEBUG_MASK_DISK_TRACE, ("Entered. Request %p\n", request)); *serviceResponse = kSCSIServiceResponse_Request_In_Process; *taskStatus = kSCSITaskStatus_No_Status; commandLength = GetCommandDescriptorBlockSize ( request ); #if 0 SCSICommandDescriptorBlock cdb = { 0 }; DbgIOLog(DEBUG_MASK_DISK_WARNING, ("Data Transfer Request %lld\n", GetRequestedDataTransferCount( request ))); GetCommandDescriptorBlock ( request, &cdb ); if ( commandLength == kSCSICDBSize_6Byte ) { DbgIOLog(DEBUG_MASK_DISK_WARNING, ("cdb = %02x:%02x:%02x:%02x:%02x:%02x\n", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5] )); } else if ( commandLength == kSCSICDBSize_10Byte ) { DbgIOLog(DEBUG_MASK_DISK_WARNING, ("cdb = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9] )); } else if ( commandLength == kSCSICDBSize_12Byte ) { DbgIOLog(DEBUG_MASK_DISK_WARNING, ("cdb = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11] )); } #endif request->retain(); if ( isInactive ()) { DbgIOLog(DEBUG_MASK_DISK_WARNING, ("Device is inactive.\n")); // device is disconnected - we can not service command request *serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; commandProcessed = false; goto exit; } // Check Workable. if (!fProvider || !fProvider->isWorkable()) { DbgIOLog(DEBUG_MASK_DISK_WARNING, ("Device is not workable.\n")); // device is disconnected - we can not service command request *serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; commandProcessed = false; goto exit; } // Check Busy. // if (fProvider->isBusy() ) if (fBusy) { DbgIOLog(DEBUG_MASK_DISK_INFO, ("Busy!!!\n")); *serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; commandProcessed = false; goto exit; } // Allocate Command. /* NDCmd_ptr = OSDynamicCast(com_ximeta_driver_NDASSCSICommand, OSMetaClass::allocClassWithName(NDAS_SCSI_COMMAND_CLASS)); if(NDCmd_ptr == NULL || !NDCmd_ptr->init()) { DbgIOLog(DEBUG_MASK_DISK_ERROR, ("failed to alloc command class\n")); if (NDCmd_ptr) { NDCmd_ptr->release(); } *serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; commandProcessed = true; goto exit; } */ NDCmd_ptr = (com_ximeta_driver_NDASSCSICommand*)fCommandPool->getCommand(false); if (NDCmd_ptr == NULL) { DbgIOLog(DEBUG_MASK_DISK_ERROR, ("No Commands.\n")); *serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; commandProcessed = true; goto exit; } NDCmd_ptr->init(); memset(&scsiCommand, 0, sizeof(SCSICommand)); scsiCommand.scsiTask = request; // scsiCommand.targetNo = fProvider->targetNo(); scsiCommand.LogicalUnitNumber = GetLogicalUnitNumber( request ); GetCommandDescriptorBlock ( request, &scsiCommand.cdb ); scsiCommand.cdbSize = commandLength; scsiCommand.MemoryDescriptor_ptr = GetDataBuffer( request ); scsiCommand.BufferOffset = GetDataBufferOffset( request ); scsiCommand.RequestedDataTransferCount = GetRequestedDataTransferCount( request ); scsiCommand.DataTransferDirection = GetDataTransferDirection( request ); // scsiCommand.BlockSize = fProvider->blocksize(); NDCmd_ptr->setCommand(&scsiCommand); // CriticalCommandSubmission(NDCmd_ptr, &commandProcessed); fBusy = true; fCommandGate->runAction ( CriticalCommandSubmissionStatic, NDCmd_ptr); //fXiCommandGate->runCommand((void *)kNDASProtocolTransportRequestSendCommand, NDCmd_ptr, &commandProcessed); exit: if ( kSCSIServiceResponse_Request_In_Process != *serviceResponse ) { DbgIOLog(DEBUG_MASK_DISK_INFO, ("ERROR Service Response = %x, task = %p\n", *serviceResponse, request)); request->release(); if(NDCmd_ptr) { NDCmd_ptr->release(); } } DbgIOLog(DEBUG_MASK_DISK_INFO,("exit, Service Response = %x, task = %p\n", *serviceResponse, request)); return commandProcessed; }
SCSIServiceResponse com_apple_dts_SCSIEmulatorAdapter::ProcessParallelTask ( SCSIParallelTaskIdentifier parallelRequest ) { // Not all of these may be required. Unused ones are commented out to avoid compiler warnings SCSITargetIdentifier targetID = GetTargetIdentifier(parallelRequest); // SCSITaskIdentifier task = GetSCSITaskIdentifier(parallelRequest); // SCSITaggedTaskIdentifier taggedTask = GetTaggedTaskIdentifier(parallelRequest); SCSILogicalUnitNumber lun = GetLogicalUnitNumber(parallelRequest); // SCSITaskAttribute taskAttribute = GetTaskAttribute(parallelRequest); UInt8 transferDir = GetDataTransferDirection(parallelRequest); UInt64 transferSize = GetRequestedDataTransferCount(parallelRequest); IOMemoryDescriptor * transferMemDesc = GetDataBuffer(parallelRequest); // UInt64 transferMemDescOffset = GetDataBufferOffset(parallelRequest); // Get the CDB UInt8 cdbLength = GetCommandDescriptorBlockSize(parallelRequest); SCSICommandDescriptorBlock cdbData; SCSITaskStatus scsiStatus = kSCSITaskStatus_GOOD; UInt64 dataLen = 0; UInt8 senseBuffer[kSenseBufferLen]; UInt64 senseBufferLen = sizeof(senseBuffer); com_apple_dts_SCSIEmulator *emulator = (com_apple_dts_SCSIEmulator *)mTargetsArray->getObject(targetID); // Fail if we don't have a SCSI emulator backing this target if (!emulator) { IOLog("ProcessParallelTask: ABORT - !emulator for targetID = %ud\n", targetID); goto failure_exit; } // Fail if we're supposed to transfer data and don't have a data buffer if (!transferMemDesc && (transferDir != kSCSIDataTransfer_NoDataTransfer)) { IOLog("ProcessParallelTask: ABORT - !transferMemDesc && (transferDir != kSCSIDataTransfer_NoDataTransfer) - %p and %d\n", transferMemDesc, transferDir); goto failure_exit; } // Fail if we don't have a large enough CDB buffer set aside if (cdbLength > sizeof(cdbData)) { IOLog("ProcessParallelTask: ABORT - cdbLength > sizeof(cdbData) - %d vs. %d\n", cdbLength, sizeof(cdbData)); goto failure_exit; } if (!GetCommandDescriptorBlock(parallelRequest, &cdbData)) { IOLog("ProcessParallelTask: ABORT - !GetCommandDescriptorBlock(parallelRequest, &cdbData)\n"); goto failure_exit; } if (transferMemDesc && (transferDir != kSCSIDataTransfer_NoDataTransfer)) { #if 0 // This block isn't necessary as memory descriptors passed in are always autoprepared for us. // Remember: Any memory descriptors allocated and used internally should be prepared before sending // or receiving data to/from real hardware IOReturn res = transferMemDesc->prepare(); if (res != kIOReturnSuccess) { goto failure_exit; } #endif // We are guaranteed that the memory descriptor will always be sized large enough by // by SAM/STUC to hold the transfer size requested dataLen = transferSize; } // This is where the "real" work should get done by your hardware. The individual parameters // are being sent instead of just the task reference as the task is opaque by design and // the getter/setter methods are protected and available within this class, but not within // the emulator itself. emulator->sendCommand(cdbData, cdbLength, transferMemDesc, &dataLen, lun, &scsiStatus, senseBuffer, &senseBufferLen); // Real hardware should be doing the task processing internally and providing responses // via an interrupt mechanism. IOSCSIParallelInterfaceController expects this and you // should always do your task completions from the workloop thread. CompleteTaskOnWorkloopThread(parallelRequest, true, scsiStatus, dataLen, senseBuffer, senseBufferLen); return kSCSIServiceResponse_Request_In_Process; failure_exit: CompleteTaskOnWorkloopThread(parallelRequest, false, scsiStatus, dataLen, senseBuffer, senseBufferLen); return kSCSIServiceResponse_Request_In_Process; }