BOOLEAN VirtIoMSInterruptRoutine ( IN PVOID DeviceExtension, IN ULONG MessageID ) { pblk_req vbr; unsigned int len; PADAPTER_EXTENSION adaptExt; PSCSI_REQUEST_BLOCK Srb; BOOLEAN isInterruptServiced = FALSE; adaptExt = (PADAPTER_EXTENSION)DeviceExtension; RhelDbgPrint(TRACE_LEVEL_VERBOSE, ("<--->%s : MessageID 0x%x\n", __FUNCTION__, MessageID)); if (MessageID == 0) { adaptExt->rescan_geometry = TRUE; StorPortNotification( BusChangeDetected, DeviceExtension, 0); return TRUE; } while((vbr = (pblk_req)adaptExt->vq->vq_ops->get_buf(adaptExt->vq, &len)) != NULL) { Srb = (PSCSI_REQUEST_BLOCK)vbr->req; if (Srb) { switch (vbr->status) { case VIRTIO_BLK_S_OK: Srb->SrbStatus = SRB_STATUS_SUCCESS; break; case VIRTIO_BLK_S_UNSUPP: Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; break; default: Srb->SrbStatus = SRB_STATUS_ERROR; RhelDbgPrint(TRACE_LEVEL_ERROR, ("SRB_STATUS_ERROR\n")); break; } } if (vbr->out_hdr.type == VIRTIO_BLK_T_FLUSH) { --adaptExt->in_fly; CompleteSRB(DeviceExtension, Srb); } else if (vbr->out_hdr.type == VIRTIO_BLK_T_GET_ID) { adaptExt->sn_ok = TRUE; } else if (Srb) { --adaptExt->in_fly; CompleteDPC(DeviceExtension, vbr, MessageID); } isInterruptServiced = TRUE; } if (adaptExt->in_fly > 0) { adaptExt->vq->vq_ops->kick(adaptExt->vq); } return isInterruptServiced; }
VOID TransportReset( IN PVOID DeviceExtension, IN PVirtIOSCSIEvent evt ) { UCHAR TargetId = evt->lun[1]; UCHAR Lun = (evt->lun[2] << 8) | evt->lun[3]; switch (evt->reason) { case VIRTIO_SCSI_EVT_RESET_RESCAN: StorPortNotification( BusChangeDetected, DeviceExtension, 0); break; case VIRTIO_SCSI_EVT_RESET_REMOVED: StorPortNotification( BusChangeDetected, DeviceExtension, 0); break; default: RhelDbgPrint(TRACE_LEVEL_VERBOSE, ("<-->Unsupport virtio scsi event reason 0x%x\n", evt->reason)); } }
VOID CompleteRequest( IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ) { ENTER_FN(); PostProcessRequest(DeviceExtension, Srb); StorPortNotification(RequestComplete, DeviceExtension, Srb); EXIT_FN(); }
VOID ParamChange( IN PVOID DeviceExtension, IN PVirtIOSCSIEvent evt ) { UCHAR TargetId = evt->lun[1]; UCHAR Lun = (evt->lun[2] << 8) | evt->lun[3]; UCHAR AdditionalSenseCode = (UCHAR)(evt->reason & 255); UCHAR AdditionalSenseCodeQualifier = (UCHAR)(evt->reason >> 8); if (AdditionalSenseCode == SCSI_ADSENSE_PARAMETERS_CHANGED && (AdditionalSenseCodeQualifier == SPC3_SCSI_SENSEQ_PARAMETERS_CHANGED || AdditionalSenseCodeQualifier == SPC3_SCSI_SENSEQ_MODE_PARAMETERS_CHANGED || AdditionalSenseCodeQualifier == SPC3_SCSI_SENSEQ_CAPACITY_DATA_HAS_CHANGED)) { StorPortNotification( BusChangeDetected, DeviceExtension, 0); } }
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().
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 AhciCompleteRequest( _In_ PAHCI_CHANNEL_EXTENSION ChannelExtension, _In_ PSTORAGE_REQUEST_BLOCK Srb, _In_ BOOLEAN AtDIRQL ) /*++ Wrapper for ComleteRequest to protect against completing the local SRB back to port driver who doesn't know anything about local SRB It assumes: SRB is completely ready to be completed back to the SRB generator It performs: 1. If Srb has completion routine, put it in completion queue. 2. Complete the command back to the owner. Do not complete the Local Srb. Called by: AhciHwStartIo RequiresControllerResources ReleaseSlottedCommand NOTE: The caller of this routine should call AhciGetNextIos or ActiveQueue to program the command (from Srb completion routine) to adapter --*/ { PAHCI_SRB_EXTENSION srbExtension = GetSrbExtension(Srb); //1. If Srb acquired active reference or has completion routine, put it in completion queue. Otherwise, complete it. if ( ((srbExtension->Flags & ATA_FLAGS_ACTIVE_REFERENCE) != 0) || (srbExtension->CompletionRoutine != NULL) ) { STOR_LOCK_HANDLE lockhandle = {0}; if (AtDIRQL == FALSE) { AhciInterruptSpinlockAcquire(ChannelExtension->AdapterExtension, ChannelExtension->PortNumber, &lockhandle); AddQueue(ChannelExtension, &ChannelExtension->CompletionQueue, Srb, 0xDEADBEEF, 0x90); AhciInterruptSpinlockRelease(ChannelExtension->AdapterExtension, ChannelExtension->PortNumber, &lockhandle); } else { AddQueue(ChannelExtension, &ChannelExtension->CompletionQueue, Srb, 0xDEADBEEF, 0x90); } if (LogExecuteFullDetail(ChannelExtension->AdapterExtension->LogFlags)) { RecordExecutionHistory(ChannelExtension, 0x30000045); //Exit AhciCompleteRequest, SRB is put in CompletionQueue } if (!IsDumpMode(ChannelExtension->AdapterExtension)) { StorPortIssueDpc(ChannelExtension->AdapterExtension, &ChannelExtension->CompletionDpc, ChannelExtension, Srb); } else { AhciPortSrbCompletionDpcRoutine(&ChannelExtension->CompletionDpc, ChannelExtension->AdapterExtension, ChannelExtension, Srb); } } else { //2. Complete the command back to the owner if (IsMiniportInternalSrb(ChannelExtension, Srb)) { NT_ASSERT(((PSCSI_REQUEST_BLOCK)Srb == &ChannelExtension->Sense.Srb) || (ChannelExtension->StateFlags.ReservedSlotInUse == 0)); RecordExecutionHistory(ChannelExtension, 0x20000045); //Exit AhciCompleteRequest, Local SRB return; } else { NT_ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING); StorPortNotification(RequestComplete, ChannelExtension->AdapterExtension, Srb); if (LogExecuteFullDetail(ChannelExtension->AdapterExtension->LogFlags)) { RecordExecutionHistory(ChannelExtension, 0x10000045); //Exit AhciCompleteRequest, SRB from port driver } } } return; }
VOID ImScsiWorkerThread(__in PVOID Context) { pHW_LU_EXTENSION pLUExt = (pHW_LU_EXTENSION)Context; pMP_WorkRtnParms pWkRtnParms = NULL; PLIST_ENTRY request_list = NULL; PKSPIN_LOCK request_list_lock = NULL; PKEVENT wait_objects[2] = { NULL }; KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY); if (pLUExt != NULL) { KdPrint(("PhDskMnt::ImScsiWorkerThread: Device worker thread start. pLUExt = 0x%p\n", pLUExt)); request_list = &pLUExt->RequestList; request_list_lock = &pLUExt->RequestListLock; wait_objects[0] = &pLUExt->RequestEvent; // If this is a VM backed disk that should be pre-loaded with an image file // we have to load the contents of that file now before entering the service // loop. if (pLUExt->VMDisk && (pLUExt->ImageFile != NULL)) if (!ImScsiFillMemoryDisk(pLUExt)) KeSetEvent(&pLUExt->StopThread, (KPRIORITY)0, FALSE); } else { KdPrint(("PhDskMnt::ImScsiWorkerThread: Global worker thread start. pLUExt=%p\n", pLUExt)); request_list = &pMPDrvInfoGlobal->RequestList; request_list_lock = &pMPDrvInfoGlobal->RequestListLock; wait_objects[0] = &pMPDrvInfoGlobal->RequestEvent; } wait_objects[1] = &pMPDrvInfoGlobal->StopWorker; for (;;) { PLIST_ENTRY request; KLOCK_QUEUE_HANDLE lock_handle; KIRQL lowest_assumed_irql = PASSIVE_LEVEL; #ifdef USE_SCSIPORT NTSTATUS status = STATUS_SUCCESS; PIRP irp = NULL; ImScsiGetControllerObject(); if (pMPDrvInfoGlobal->ControllerObject != NULL) { KdPrint2(("PhDskMnt::ImScsiWorkerThread: Pre-building IRP for next SMB_IMSCSI_CHECK.\n")); irp = ImScsiBuildCompletionIrp(); } #endif for (;;) { ImScsiAcquireLock(request_list_lock, &lock_handle, lowest_assumed_irql); request = RemoveHeadList(request_list); ImScsiReleaseLock(&lock_handle, &lowest_assumed_irql); if (request != request_list) { break; } if (KeReadStateEvent(&pMPDrvInfoGlobal->StopWorker) || ((pLUExt != NULL) && (KeReadStateEvent(&pLUExt->StopThread)))) { KdPrint(("PhDskMnt::ImScsiWorkerThread shutting down.\n")); if (pLUExt != NULL) { KIRQL lowest_assumed_irql = PASSIVE_LEVEL; ImScsiCleanupLU(pLUExt, &lowest_assumed_irql); } #ifdef USE_SCSIPORT // One last SMB_IMSCSI_CHECK call to flush response queue and free allocated IRP if (irp != NULL) { IoCallDriver(pMPDrvInfoGlobal->ControllerObject, irp); } #endif PsTerminateSystemThread(STATUS_SUCCESS); return; } KdPrint2(("PhDskMnt::ImScsiWorkerThread idle, waiting for request.\n")); KeWaitForMultipleObjects(2, (PVOID*)wait_objects, WaitAny, Executive, KernelMode, FALSE, NULL, NULL); } pWkRtnParms = CONTAINING_RECORD(request, MP_WorkRtnParms, RequestListEntry); KdPrint2(("PhDskMnt::ImScsiWorkerThread got request. pWkRtnParms = 0x%p\n", pWkRtnParms)); // Request to wait for LU worker thread to terminate if (pWkRtnParms->pSrb == NULL) { KdPrint(("PhDskMnt::ImScsiWorkerThread: Request to wait for LU worker thread to exit. pLUExt=%p\n", pWkRtnParms->pLUExt)); if (pWkRtnParms->pLUExt->WorkerThread != NULL) { KeWaitForSingleObject( pWkRtnParms->pLUExt->WorkerThread, Executive, KernelMode, FALSE, NULL); ObDereferenceObject(pWkRtnParms->pLUExt->WorkerThread); pWkRtnParms->pLUExt->WorkerThread = NULL; KdPrint(("PhDskMnt::ImScsiWorkerThread: Worker thread exit. Ready to free LUExt.\n")); } else { KdPrint(("PhDskMnt::ImScsiWorkerThread: Worker not started. Ready to free LUExt.\n")); } ExFreePoolWithTag(pWkRtnParms->pLUExt, MP_TAG_GENERAL); ExFreePoolWithTag(pWkRtnParms, MP_TAG_GENERAL); continue; } ImScsiDispatchWork(pWkRtnParms); #ifdef USE_SCSIPORT KdPrint2(("PhDskMnt::ImScsiWorkerThread: Calling SMB_IMSCSI_CHECK for work: 0x%p.\n", pWkRtnParms)); status = ImScsiCallForCompletion(irp, pWkRtnParms, &lowest_assumed_irql); if (!NT_SUCCESS(status)) DbgPrint("PhDskMnt::ImScsiWorkerThread: IoCallDriver failed: 0x%X for work 0x%p\n", status, pWkRtnParms); else KdPrint2(("PhDskMnt::ImScsiWorkerThread: Finished SMB_IMSCSI_CHECK for work: 0x%p.\n", pWkRtnParms)); #endif #ifdef USE_STORPORT KdPrint2(("PhDskMnt::ImScsiWorkerThread: Sending 'RequestComplete' to StorPort for work: 0x%p.\n", pWkRtnParms)); StorPortNotification(RequestComplete, pWkRtnParms->pHBAExt, pWkRtnParms->pSrb); ExFreePoolWithTag(pWkRtnParms, MP_TAG_GENERAL); KdPrint2(("PhDskMnt::ImScsiWorkerThread: Finished work: 0x%p.\n", pWkRtnParms)); #endif } }
BOOLEAN VioScsiBuildIo( IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ) { PCDB cdb; ULONG i; ULONG fragLen; ULONG sgElement; ULONG sgMaxElements; PADAPTER_EXTENSION adaptExt; PSRB_EXTENSION srbExt; PSTOR_SCATTER_GATHER_LIST sgList; VirtIOSCSICmd *cmd; ENTER_FN(); cdb = (PCDB)&Srb->Cdb[0]; srbExt = (PSRB_EXTENSION)Srb->SrbExtension; adaptExt = (PADAPTER_EXTENSION)DeviceExtension; if( (Srb->PathId > 0) || (Srb->TargetId >= adaptExt->scsi_config.max_target) || (Srb->Lun >= adaptExt->scsi_config.max_lun) ) { Srb->SrbStatus = SRB_STATUS_NO_DEVICE; StorPortNotification(RequestComplete, DeviceExtension, Srb); return FALSE; } RhelDbgPrint(TRACE_LEVEL_VERBOSE, ("<-->%s (%d::%d::%d)\n", DbgGetScsiOpStr(Srb), Srb->PathId, Srb->TargetId, Srb->Lun)); memset(srbExt, 0, sizeof(*srbExt)); cmd = &srbExt->cmd; cmd->sc = Srb; cmd->req.cmd.lun[0] = 1; cmd->req.cmd.lun[1] = Srb->TargetId; cmd->req.cmd.lun[2] = 0; cmd->req.cmd.lun[3] = Srb->Lun; cmd->req.cmd.tag = (unsigned long)Srb; cmd->req.cmd.task_attr = VIRTIO_SCSI_S_SIMPLE; cmd->req.cmd.prio = 0; cmd->req.cmd.crn = 0; memcpy(cmd->req.cmd.cdb, cdb, min(VIRTIO_SCSI_CDB_SIZE, Srb->CdbLength)); sgElement = 0; srbExt->sg[sgElement].physAddr = StorPortGetPhysicalAddress(DeviceExtension, NULL, &cmd->req.cmd, &fragLen); srbExt->sg[sgElement].ulSize = sizeof(cmd->req.cmd); sgElement++; sgList = StorPortGetScatterGatherList(DeviceExtension, Srb); if (sgList) { sgMaxElements = sgList->NumberOfElements; if((Srb->SrbFlags & SRB_FLAGS_DATA_OUT) == SRB_FLAGS_DATA_OUT) { for (i = 0; i < sgMaxElements; i++, sgElement++) { srbExt->sg[sgElement].physAddr = sgList->List[i].PhysicalAddress; srbExt->sg[sgElement].ulSize = sgList->List[i].Length; srbExt->Xfer += sgList->List[i].Length; } } } srbExt->out = sgElement; srbExt->sg[sgElement].physAddr = StorPortGetPhysicalAddress(DeviceExtension, NULL, &cmd->resp.cmd, &fragLen); srbExt->sg[sgElement].ulSize = sizeof(cmd->resp.cmd); sgElement++; if (sgList) { sgMaxElements = sgList->NumberOfElements; if((Srb->SrbFlags & SRB_FLAGS_DATA_OUT) != SRB_FLAGS_DATA_OUT) { for (i = 0; i < sgMaxElements; i++, sgElement++) { srbExt->sg[sgElement].physAddr = sgList->List[i].PhysicalAddress; srbExt->sg[sgElement].ulSize = sgList->List[i].Length; srbExt->Xfer += sgList->List[i].Length; } } } srbExt->in = sgElement - srbExt->out; EXIT_FN(); return TRUE; }
BOOLEAN VioScsiMSInterrupt ( IN PVOID DeviceExtension, IN ULONG MessageID ) { PVirtIOSCSICmd cmd; PVirtIOSCSIEventNode evtNode; unsigned int len; PADAPTER_EXTENSION adaptExt; BOOLEAN isInterruptServiced = FALSE; PSCSI_REQUEST_BLOCK Srb; PSRB_EXTENSION srbExt; ULONG intReason = 0; adaptExt = (PADAPTER_EXTENSION)DeviceExtension; RhelDbgPrint(TRACE_LEVEL_VERBOSE, ("<--->%s : MessageID 0x%x\n", __FUNCTION__, MessageID)); if (MessageID == 0) { return TRUE; } if (MessageID == 1) { if (adaptExt->tmf_infly) { while((cmd = (PVirtIOSCSICmd)adaptExt->vq[0]->vq_ops->get_buf(adaptExt->vq[0], &len)) != NULL) { VirtIOSCSICtrlTMFResp *resp; Srb = (PSCSI_REQUEST_BLOCK)cmd->sc; ASSERT(Srb == &adaptExt->tmf_cmd.Srb); resp = &cmd->resp.tmf; switch(resp->response) { case VIRTIO_SCSI_S_OK: case VIRTIO_SCSI_S_FUNCTION_SUCCEEDED: break; default: RhelDbgPrint(TRACE_LEVEL_ERROR, ("Unknown response %d\n", resp->response)); ASSERT(0); break; } StorPortResume(DeviceExtension); } adaptExt->tmf_infly = FALSE; } return TRUE; } if (MessageID == 2) { while((evtNode = (PVirtIOSCSIEventNode)adaptExt->vq[1]->vq_ops->get_buf(adaptExt->vq[1], &len)) != NULL) { PVirtIOSCSIEvent evt = &evtNode->event; switch (evt->event) { case VIRTIO_SCSI_T_NO_EVENT: break; case VIRTIO_SCSI_T_TRANSPORT_RESET: TransportReset(DeviceExtension, evt); break; case VIRTIO_SCSI_T_PARAM_CHANGE: ParamChange(DeviceExtension, evt); break; default: RhelDbgPrint(TRACE_LEVEL_ERROR, ("Unsupport virtio scsi event %x\n", evt->event)); break; } SynchronizedKickEventRoutine(DeviceExtension, evtNode); } return TRUE; } if (MessageID == 3) { while((cmd = (PVirtIOSCSICmd)adaptExt->vq[2]->vq_ops->get_buf(adaptExt->vq[2], &len)) != NULL) { VirtIOSCSICmdResp *resp; Srb = (PSCSI_REQUEST_BLOCK)cmd->sc; resp = &cmd->resp.cmd; srbExt = (PSRB_EXTENSION)Srb->SrbExtension; switch (resp->response) { case VIRTIO_SCSI_S_OK: Srb->ScsiStatus = resp->status; Srb->SrbStatus = (Srb->ScsiStatus == SCSISTAT_GOOD) ? SRB_STATUS_SUCCESS : SRB_STATUS_ERROR; break; case VIRTIO_SCSI_S_UNDERRUN: RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("VIRTIO_SCSI_S_UNDERRUN\n")); Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; break; case VIRTIO_SCSI_S_ABORTED: RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("VIRTIO_SCSI_S_ABORTED\n")); Srb->SrbStatus = SRB_STATUS_ABORTED; break; case VIRTIO_SCSI_S_BAD_TARGET: RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("VIRTIO_SCSI_S_BAD_TARGET\n")); Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID; break; case VIRTIO_SCSI_S_RESET: RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("VIRTIO_SCSI_S_RESET\n")); Srb->SrbStatus = SRB_STATUS_BUS_RESET; break; case VIRTIO_SCSI_S_BUSY: RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("VIRTIO_SCSI_S_BUSY\n")); Srb->SrbStatus = SRB_STATUS_BUSY; break; case VIRTIO_SCSI_S_TRANSPORT_FAILURE: RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("VIRTIO_SCSI_S_TRANSPORT_FAILURE\n")); Srb->SrbStatus = SRB_STATUS_ERROR; break; case VIRTIO_SCSI_S_TARGET_FAILURE: RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("VIRTIO_SCSI_S_TARGET_FAILURE\n")); Srb->SrbStatus = SRB_STATUS_ERROR; break; case VIRTIO_SCSI_S_NEXUS_FAILURE: RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("VIRTIO_SCSI_S_NEXUS_FAILURE\n")); Srb->SrbStatus = SRB_STATUS_ERROR; break; case VIRTIO_SCSI_S_FAILURE: RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("VIRTIO_SCSI_S_FAILURE\n")); Srb->SrbStatus = SRB_STATUS_ERROR; break; default: Srb->SrbStatus = SRB_STATUS_ERROR; RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("Unknown response %d\n", resp->response)); break; } if (Srb->SrbStatus != SRB_STATUS_SUCCESS) { PSENSE_DATA pSense = (PSENSE_DATA) Srb->SenseInfoBuffer; if (Srb->SenseInfoBufferLength >= FIELD_OFFSET(SENSE_DATA, CommandSpecificInformation)) { memcpy(Srb->SenseInfoBuffer, resp->sense, min(resp->sense_len, Srb->SenseInfoBufferLength)); if (Srb->SrbStatus == SRB_STATUS_ERROR) { Srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID; } } Srb->DataTransferLength = 0; } else if (srbExt->Xfer && Srb->DataTransferLength > srbExt->Xfer) { Srb->DataTransferLength = srbExt->Xfer; Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; } if (srbExt && srbExt->Xfer && Srb->DataTransferLength > srbExt->Xfer) { Srb->DataTransferLength = srbExt->Xfer; Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; } --adaptExt->in_fly; StorPortNotification(RequestComplete, DeviceExtension, Srb); if (adaptExt->in_fly > 0) { adaptExt->vq[2]->vq_ops->kick(adaptExt->vq[2]); } } return TRUE; } return FALSE; }