int AppleSCSIPDT03Emulator::SendCommand ( UInt8 * cdb, UInt8 cbdLen, IOMemoryDescriptor * dataDesc, UInt64 * dataLen, SCSITaskStatus * scsiStatus, SCSI_Sense_Data * senseBuffer, UInt8 * senseBufferLen ) { STATUS_LOG ( ( "AppleSCSIPDT03Emulator::SendCommand, LUN = %qd\n", GetLogicalUnitNumber ( ) ) ); switch ( cdb[0] ) { case kSCSICmd_TEST_UNIT_READY: { COMMAND_LOG ( ( "SCSI Command: TEST_UNIT_READY\n" ) ); *scsiStatus = kSCSITaskStatus_GOOD; *dataLen = 0; break; } case kSCSICmd_INQUIRY: { COMMAND_LOG ( ( "SCSI Command: INQUIRY\n" ) ); if ( cdb[1] == 1 ) { COMMAND_LOG ( ( "INQUIRY VPD requested, PDT03 doesn't support it\n" ) ); *scsiStatus = kSCSITaskStatus_CHECK_CONDITION; if ( senseBuffer != NULL ) { UInt8 amount = min ( *senseBufferLen, sizeof ( SCSI_Sense_Data ) ); bzero ( senseBuffer, *senseBufferLen ); bcopy ( &gInvalidCDBFieldSenseData, senseBuffer, amount ); *senseBufferLen = amount; } } else if ( ( cdb[1] == 2 ) || ( cdb[2] != 0 ) || ( cdb[3] != 0 ) ) { COMMAND_LOG ( ( "Illegal request\n" ) ); // Don't support CMDDT bit, or PAGE_CODE without EVPD set. *scsiStatus = kSCSITaskStatus_CHECK_CONDITION; if ( senseBuffer != NULL ) { UInt8 amount = min ( *senseBufferLen, sizeof ( SCSI_Sense_Data ) ); bzero ( senseBuffer, *senseBufferLen ); bcopy ( &gInvalidCDBFieldSenseData, senseBuffer, amount ); *senseBufferLen = amount; } } else { COMMAND_LOG ( ( "Standard INQUIRY\n" ) ); *dataLen = min ( sizeof ( sInquiryData ), *dataLen ); dataDesc->writeBytes ( 0, &sInquiryData, *dataLen ); *scsiStatus = kSCSITaskStatus_GOOD; } } break; case kSCSICmd_REQUEST_SENSE: { COMMAND_LOG ( ( "SCSI Command: REQUEST_SENSE (desc = %s, allocation length = %d bytes) - returning CHECK CONDITION with INVALID COMMAND\n", (cdb[1] & 0x01) ? "TRUE" : "FALSE", cdb[4] ) ); *scsiStatus = kSCSITaskStatus_CHECK_CONDITION; *dataLen = 0; if ( senseBuffer != NULL ) { UInt8 amount = min ( *senseBufferLen, sizeof ( SCSI_Sense_Data ) ); bzero ( senseBuffer, *senseBufferLen ); bcopy ( &gInvalidCommandSenseData, senseBuffer, amount ); *senseBufferLen = amount; } } break; default: { COMMAND_LOG ( ( "SCSI Command: Unknown: 0x%X\n", cdb[0] ) ); *scsiStatus = kSCSITaskStatus_CHECK_CONDITION; if ( senseBuffer != NULL ) { UInt8 amount = min ( *senseBufferLen, sizeof ( SCSI_Sense_Data ) ); bzero ( senseBuffer, *senseBufferLen ); bcopy ( &gInvalidCommandSenseData, senseBuffer, amount ); *senseBufferLen = amount; } } break; } return 1; }
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; }