static struct virtqueue *FindVirtualQueue(PADAPTER_EXTENSION adaptExt, ULONG index, ULONG vector) { struct virtqueue *vq = NULL; if (adaptExt->uncachedExtensionVa) { ULONG len; PHYSICAL_ADDRESS pa = ScsiPortGetPhysicalAddress(adaptExt, NULL, adaptExt->uncachedExtensionVa, &len); if (pa.QuadPart) vq = VirtIODevicePrepareQueue(&adaptExt->vdev, index, pa, adaptExt->uncachedExtensionVa, len, NULL); } if (vq && vector) { unsigned res; ScsiPortWritePortUshort((PUSHORT)(adaptExt->vdev.addr + VIRTIO_MSI_QUEUE_VECTOR),(USHORT)vector); res = ScsiPortReadPortUshort((PUSHORT)(adaptExt->vdev.addr + VIRTIO_MSI_QUEUE_VECTOR)); RhelDbgPrint(TRACE_LEVEL_FATAL, ("%s>> VIRTIO_MSI_QUEUE_VECTOR vector = %d, res = 0x%x\n", __FUNCTION__, vector, res)); if(res == VIRTIO_MSI_NO_VECTOR) { VirtIODeviceDeleteQueue(vq, NULL); vq = NULL; RhelDbgPrint(TRACE_LEVEL_FATAL, ("%s>> Cannot create vq vector\n", __FUNCTION__)); return NULL; } } return vq; }
void GetXferSegment (const ADAPTER_PTR HA, IO_REQ_PTR Req, SegmentDescr *SGDescr, U32 Offset, BOOLEAN DemandPhysicalAddr) { TRACE(4, ("GetXferSegment(): Offset = %d\n", Offset)); TRACE(4, ("GetXferSegment(): Non-S/G request, ReqDataCount = %d\n", ReqDataCount(Req))); if (Offset < ReqDataCount(Req)) { // Make sure we don't over run SGDescr->SegmentLength = ReqDataCount(Req) - Offset; SGDescr->SegmentPtr = (U32)ReqDataPtr(Req) + Offset; } else { SGDescr->SegmentLength = 0; // No data left SGDescr->SegmentPtr = 0; BreakPoint(HA); } TRACE(4, ("GetXferSegment(): %d bytes remain in segment at %08x (offset %d)\n", SGDescr->SegmentLength, SGDescr->SegmentPtr, Offset)); SGDescr->Flags.IsPhysical = FALSE; if (DemandPhysicalAddr) { if (ReqState(Req).InternalRequest) { TRACE(5, ("GetXferSegment(): Mapping internal request\n")); MapToPhysical(HA, SGDescr); } else { ULONG Size = SGDescr->SegmentLength; SGDescr->SegmentPtr = (U32)ScsiPortConvertPhysicalAddressToUlong( ScsiPortGetPhysicalAddress(HA, Req, (PVOID)((U32)ReqDataPtr(Req) + Offset) /*(SGDescr->SegmentPtr)*/, &Size)); if (Size < SGDescr->SegmentLength) SGDescr->SegmentLength = Size; DEBUG(5, { if (SGDescr->SegmentLength < (ReqDataCount(Req) - Offset)) DPrintf("Segment length is %d out of %d\n", SGDescr->SegmentLength, ReqDataCount(Req) - Offset);}); SGDescr->Flags.IsPhysical = TRUE; TRACE(5, ("GetXferSegment(): Mapped to 0x%lx for %lu bytes\n", SGDescr->SegmentPtr, Size)); } }
BOOLEAN SynchronizedFlushRoutine( IN PVOID DeviceExtension, IN PVOID Context ) { PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension; PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK) Context; PRHEL_SRB_EXTENSION srbExt = (PRHEL_SRB_EXTENSION)Srb->SrbExtension; ULONG fragLen; PVOID va; ULONGLONG pa; SET_VA_PA(); srbExt->vbr.out_hdr.sector = 0; srbExt->vbr.out_hdr.ioprio = 0; srbExt->vbr.req = (struct request *)Srb; srbExt->vbr.out_hdr.type = VIRTIO_BLK_T_FLUSH; srbExt->out = 1; srbExt->in = 1; srbExt->vbr.sg[0].physAddr = ScsiPortGetPhysicalAddress(DeviceExtension, NULL, &srbExt->vbr.out_hdr, &fragLen); srbExt->vbr.sg[0].length = sizeof(srbExt->vbr.out_hdr); srbExt->vbr.sg[1].physAddr = ScsiPortGetPhysicalAddress(DeviceExtension, NULL, &srbExt->vbr.status, &fragLen); srbExt->vbr.sg[1].length = sizeof(srbExt->vbr.status); if (virtqueue_add_buf(adaptExt->vq, &srbExt->vbr.sg[0], srbExt->out, srbExt->in, &srbExt->vbr, va, pa) >= 0) { virtqueue_kick(adaptExt->vq); return TRUE; } virtqueue_kick(adaptExt->vq); #ifdef USE_STORPORT StorPortBusy(DeviceExtension, 2); #endif return FALSE; }
BOOLEAN VirtIoBuildIo( IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ) { PCDB cdb; ULONG i; ULONG dummy; ULONG sgElement; ULONG sgMaxElements; PADAPTER_EXTENSION adaptExt; PRHEL_SRB_EXTENSION srbExt; PSTOR_SCATTER_GATHER_LIST sgList; cdb = (PCDB)&Srb->Cdb[0]; srbExt = (PRHEL_SRB_EXTENSION)Srb->SrbExtension; adaptExt = (PADAPTER_EXTENSION)DeviceExtension; if(Srb->PathId || Srb->TargetId || Srb->Lun) { Srb->SrbStatus = SRB_STATUS_NO_DEVICE; ScsiPortNotification(RequestComplete, DeviceExtension, Srb); return FALSE; } switch (cdb->CDB6GENERIC.OperationCode) { case SCSIOP_READ: case SCSIOP_WRITE: case SCSIOP_WRITE_VERIFY: case SCSIOP_READ6: case SCSIOP_WRITE6: case SCSIOP_READ12: case SCSIOP_WRITE12: case SCSIOP_WRITE_VERIFY12: case SCSIOP_READ16: case SCSIOP_WRITE16: case SCSIOP_WRITE_VERIFY16: { break; } default: { Srb->SrbStatus = SRB_STATUS_SUCCESS; return TRUE; } } sgList = StorPortGetScatterGatherList(DeviceExtension, Srb); sgMaxElements = min((MAX_PHYS_SEGMENTS + 1), sgList->NumberOfElements); srbExt->Xfer = 0; for (i = 0, sgElement = 1; i < sgMaxElements; i++, sgElement++) { srbExt->vbr.sg[sgElement].physAddr = sgList->List[i].PhysicalAddress; srbExt->vbr.sg[sgElement].ulSize = sgList->List[i].Length; srbExt->Xfer += sgList->List[i].Length; } srbExt->vbr.out_hdr.sector = RhelGetLba(DeviceExtension, cdb); srbExt->vbr.out_hdr.ioprio = 0; srbExt->vbr.req = (PVOID)Srb; srbExt->fua = (cdb->CDB10.ForceUnitAccess == 1); if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) { srbExt->vbr.out_hdr.type = VIRTIO_BLK_T_OUT; srbExt->out = sgElement; srbExt->in = 1; } else { srbExt->vbr.out_hdr.type = VIRTIO_BLK_T_IN; srbExt->out = 1; srbExt->in = sgElement; } srbExt->vbr.sg[0].physAddr = ScsiPortGetPhysicalAddress(DeviceExtension, NULL, &srbExt->vbr.out_hdr, &dummy); srbExt->vbr.sg[0].ulSize = sizeof(srbExt->vbr.out_hdr); srbExt->vbr.sg[sgElement].physAddr = ScsiPortGetPhysicalAddress(DeviceExtension, NULL, &srbExt->vbr.status, &dummy); srbExt->vbr.sg[sgElement].ulSize = sizeof(srbExt->vbr.status); return TRUE; }
static ULONGLONG mem_get_physical_address(void *context, void *virt) { ULONG uLength; SCSI_PHYSICAL_ADDRESS pa = ScsiPortGetPhysicalAddress(context, NULL, virt, &uLength); return pa.QuadPart; }
BOOLEAN RhelDoReadWrite(PVOID DeviceExtension, PSCSI_REQUEST_BLOCK Srb) { PCDB cdb; ULONG fragLen; ULONG sgElement; ULONG BytesLeft; PVOID DataBuffer; PADAPTER_EXTENSION adaptExt; PRHEL_SRB_EXTENSION srbExt; int num_free; PVOID va; ULONGLONG pa; ULONG i; ULONG sgMaxElements; cdb = (PCDB)&Srb->Cdb[0]; srbExt = (PRHEL_SRB_EXTENSION)Srb->SrbExtension; adaptExt = (PADAPTER_EXTENSION)DeviceExtension; BytesLeft= Srb->DataTransferLength; DataBuffer = Srb->DataBuffer; memset(srbExt, 0, sizeof (RHEL_SRB_EXTENSION)); sgMaxElements = MAX_PHYS_SEGMENTS + 1; for (i = 0, sgElement = 1; (i < sgMaxElements) && BytesLeft; i++, sgElement++) { srbExt->vbr.sg[sgElement].physAddr = ScsiPortGetPhysicalAddress(DeviceExtension, Srb, DataBuffer, &fragLen); srbExt->vbr.sg[sgElement].ulSize = fragLen; srbExt->Xfer += fragLen; BytesLeft -= fragLen; DataBuffer = (PVOID)((ULONG_PTR)DataBuffer + fragLen); } srbExt->vbr.out_hdr.sector = RhelGetLba(DeviceExtension, cdb); srbExt->vbr.out_hdr.ioprio = 0; srbExt->vbr.req = (struct request *)Srb; if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) { srbExt->vbr.out_hdr.type = VIRTIO_BLK_T_OUT; srbExt->out = sgElement; srbExt->in = 1; } else { srbExt->vbr.out_hdr.type = VIRTIO_BLK_T_IN; srbExt->out = 1; srbExt->in = sgElement; } srbExt->vbr.sg[0].physAddr = ScsiPortGetPhysicalAddress(DeviceExtension, NULL, &srbExt->vbr.out_hdr, &fragLen); srbExt->vbr.sg[0].ulSize = sizeof(srbExt->vbr.out_hdr); srbExt->vbr.sg[sgElement].physAddr = ScsiPortGetPhysicalAddress(DeviceExtension, NULL, &srbExt->vbr.status, &fragLen); srbExt->vbr.sg[sgElement].ulSize = sizeof(srbExt->vbr.status); SET_VA_PA(); num_free = adaptExt->vq->vq_ops->add_buf(adaptExt->vq, &srbExt->vbr.sg[0], srbExt->out, srbExt->in, &srbExt->vbr, va, pa); if ( num_free >= 0) { InsertTailList(&adaptExt->list_head, &srbExt->vbr.list_entry); adaptExt->vq->vq_ops->kick(adaptExt->vq); srbExt->call_next = FALSE; if(!adaptExt->indirect && num_free < VIRTIO_MAX_SG) { srbExt->call_next = TRUE; } else { ScsiPortNotification(NextLuRequest, DeviceExtension, Srb->PathId, Srb->TargetId, Srb->Lun); } } return TRUE; }
BOOLEAN VirtIoBuildIo( IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ) { PCDB cdb; ULONG i; ULONG dummy; ULONG sgElement; ULONG sgMaxElements; PADAPTER_EXTENSION adaptExt; PRHEL_SRB_EXTENSION srbExt; PSTOR_SCATTER_GATHER_LIST sgList; ULONGLONG lba; ULONG blocks; cdb = (PCDB)&Srb->Cdb[0]; srbExt = (PRHEL_SRB_EXTENSION)Srb->SrbExtension; adaptExt = (PADAPTER_EXTENSION)DeviceExtension; if(Srb->PathId || Srb->TargetId || Srb->Lun) { Srb->SrbStatus = SRB_STATUS_NO_DEVICE; ScsiPortNotification(RequestComplete, DeviceExtension, Srb); return FALSE; } switch (cdb->CDB6GENERIC.OperationCode) { case SCSIOP_READ: case SCSIOP_WRITE: case SCSIOP_WRITE_VERIFY: case SCSIOP_READ6: case SCSIOP_WRITE6: case SCSIOP_READ12: case SCSIOP_WRITE12: case SCSIOP_WRITE_VERIFY12: case SCSIOP_READ16: case SCSIOP_WRITE16: case SCSIOP_WRITE_VERIFY16: { break; } default: { Srb->SrbStatus = SRB_STATUS_SUCCESS; return TRUE; } } lba = RhelGetLba(DeviceExtension, cdb); blocks = (Srb->DataTransferLength + adaptExt->info.blk_size - 1) / adaptExt->info.blk_size; if (lba > adaptExt->lastLBA) { RhelDbgPrint(TRACE_LEVEL_ERROR, ("SRB_STATUS_BAD_SRB_BLOCK_LENGTH lba = %llu lastLBA= %llu\n", lba, adaptExt->lastLBA)); Srb->SrbStatus = SRB_STATUS_BAD_SRB_BLOCK_LENGTH; CompleteSRB(DeviceExtension, Srb); return FALSE; } if ((lba + blocks) > adaptExt->lastLBA) { blocks = (ULONG)(adaptExt->lastLBA + 1 - lba); RhelDbgPrint(TRACE_LEVEL_ERROR, ("lba = %llu lastLBA= %llu blocks = %lu\n", lba, adaptExt->lastLBA, blocks)); Srb->DataTransferLength = (ULONG)(blocks * adaptExt->info.blk_size); } sgList = StorPortGetScatterGatherList(DeviceExtension, Srb); sgMaxElements = min((MAX_PHYS_SEGMENTS + 1), sgList->NumberOfElements); srbExt->Xfer = 0; for (i = 0, sgElement = 1; i < sgMaxElements; i++, sgElement++) { srbExt->vbr.sg[sgElement].physAddr = sgList->List[i].PhysicalAddress; srbExt->vbr.sg[sgElement].length = sgList->List[i].Length; srbExt->Xfer += sgList->List[i].Length; } srbExt->vbr.out_hdr.sector = lba; srbExt->vbr.out_hdr.ioprio = 0; srbExt->vbr.req = (PVOID)Srb; srbExt->fua = (cdb->CDB10.ForceUnitAccess == 1); if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) { srbExt->vbr.out_hdr.type = VIRTIO_BLK_T_OUT; srbExt->out = sgElement; srbExt->in = 1; } else { srbExt->vbr.out_hdr.type = VIRTIO_BLK_T_IN; srbExt->out = 1; srbExt->in = sgElement; } srbExt->vbr.sg[0].physAddr = ScsiPortGetPhysicalAddress(DeviceExtension, NULL, &srbExt->vbr.out_hdr, &dummy); srbExt->vbr.sg[0].length = sizeof(srbExt->vbr.out_hdr); srbExt->vbr.sg[sgElement].physAddr = ScsiPortGetPhysicalAddress(DeviceExtension, NULL, &srbExt->vbr.status, &dummy); srbExt->vbr.sg[sgElement].length = sizeof(srbExt->vbr.status); return TRUE; }
ULONG Wd7000ExFindAdapter( IN PVOID HwDeviceExtension, IN PVOID Context, IN PVOID BusInformation, IN PCHAR ArgumentString, IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, OUT PBOOLEAN Again ) /*++ Routine Description: This function is called by the OS-specific port driver after the necessary storage has been allocated, to gather information about the adapter's configuration. Arguments: HwDeviceExtension - HBA miniport driver's adapter data storage ConfigInfo - Configuration information structure describing HBA Return Value: TRUE if adapter present in system --*/ { PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; PEISA_CONTROLLER eisaController; PULONG adapterCount = Context; PNONCACHED_EXTENSION ncExtension; ULONG eisaSlotNumber; PICB icb; PADAPTER_INQUIRY adapterInquiry; ULONG physicalIcb; ULONG i; ULONG length; UCHAR status; // // Check to see if adapter present in system. // if (!AdapterPresent(deviceExtension, ConfigInfo, Context)) { DebugPrint((1,"Wd7000EX: SCSI adapter not present\n")); *Again = FALSE; return SP_RETURN_NOT_FOUND; } // // There is still more to look at. // *Again = FALSE; // // Fill in the access array information only if there are no // default parameters already there. // if (ScsiPortConvertPhysicalAddressToUlong( (*ConfigInfo->AccessRanges)[0].RangeStart) == 0) { *Again = TRUE; (*ConfigInfo->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x1000 * (*((PULONG) Context)) + EISA_ADDRESS_BASE); (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(EISA_CONTROLLER); (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE; // // Indicate maximum transfer length in bytes. // ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_SIZE; // // Maximum number of physical segments is 32. // ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SDL_SIZE; // // Set the configuration parameters for this card. // ConfigInfo->NumberOfBuses = 1; deviceExtension->NumberOfBuses = 1; ConfigInfo->ScatterGather = TRUE; ConfigInfo->Master = TRUE; // // Get a noncached extension for an adapter inquiry command. // ncExtension = ScsiPortGetUncachedExtension( deviceExtension, ConfigInfo, sizeof(NONCACHED_EXTENSION)); if (ncExtension == NULL) { // // Log error. // ScsiPortLogError( deviceExtension, NULL, 0, 0, 0, SP_INTERNAL_ADAPTER_ERROR, 6 << 16 ); return SP_RETURN_ERROR; } length = sizeof(NONCACHED_EXTENSION); // // Convert virtual to physical address. // physicalIcb = ScsiPortConvertPhysicalAddressToUlong( ScsiPortGetPhysicalAddress(deviceExtension, NULL, ncExtension, &length)); // // Initialize the pointers. // icb = &ncExtension->Icb; adapterInquiry = &ncExtension->AdapterInquiry; // // Create ICB for Adapter Inquiry Command. // icb->IcbFlags = 0; icb->CompletionStatus = 0; icb->Reserved = 0; icb->DataBufferAddress = ScsiPortConvertPhysicalAddressToUlong( ScsiPortGetPhysicalAddress( deviceExtension, NULL, adapterInquiry, &length)); icb->TransferCount = sizeof(ADAPTER_INQUIRY); icb->OpCode = ADAPTER_INQUIRY_COMMAND; // // Get ICB physical address. // physicalIcb = ScsiPortConvertPhysicalAddressToUlong( ScsiPortGetPhysicalAddress( deviceExtension, NULL, icb, &length)); // // Disable system interrupts. // ScsiPortWritePortUchar(&deviceExtension->EisaController->SystemInterruptEnable, SYSTEM_INTERRUPTS_DISABLE); // // Write ICB physical address and command to mailbox. // SendCommand(PROCESS_ICB, physicalIcb, deviceExtension); // // Poll for ICB completion. // i = 0; while ((status = ScsiPortReadPortUchar( &deviceExtension->EisaController->ResponseRegister)) == 0) { i++; if (i > 100000) { break; } ScsiPortStallExecution(10); } if (status == 0) { // // The request timed out. Log an error and return. // ScsiPortLogError( deviceExtension, NULL, 0, 0, 0, SP_INTERNAL_ADAPTER_ERROR, 7 << 16 ); return SP_RETURN_ERROR; } DebugPrint((1, "Wd7000ExFindAdapter: Get configuration request time = %d.\n", i * 10)); // // Acknowledge interrupt. // ScsiPortWritePortUchar(&deviceExtension->EisaController->ResponseRegister, 0xFF); // // Enable system interrupts. // ScsiPortWritePortUchar(&deviceExtension->EisaController->SystemInterruptEnable, SYSTEM_INTERRUPTS_ENABLE); // // Check returned status for success. // if (status != COMPLETE_SUCCESS) { // // Give up. // DebugPrint((1,"Wd7000Ex: Response register %x\n", status)); DebugPrint((1,"Wd7000Ex: Adapter inquiry failed\n")); // // Log error. // ScsiPortLogError( deviceExtension, NULL, 0, 0, 0, SP_INTERNAL_ADAPTER_ERROR, 8 << 16 ); return SP_RETURN_ERROR; } // // NOTE: Delay here. I don't understand this latency between // when the device interrupts and the status of the ICB // is success and when the data is actually available in // the buffer. // ScsiPortStallExecution(300); if (adapterInquiry->AdapterInformation & DUAL_CHANNEL) { // // There are two buses on the adapter. // ConfigInfo->InitiatorBusId[1] = (adapterInquiry->ChannelInformation >> 4) & BUS_ID_MASK; ConfigInfo->NumberOfBuses = 2; deviceExtension->NumberOfBuses = 2; }