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;
}
Example #2
0
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;
}
Example #8
0
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;
        }