Example #1
0
VirtioBlk::VirtioBlk(hw::PCI_Device& d)
  : Virtio(d), hw::Drive(), req(queue_size(0), 0, iobase()), inflight(0)
{
  INFO("VirtioBlk", "Driver initializing");
  {
    auto& reqs = Statman::get().create(
      Stat::UINT32, blkname() + ".requests");
    this->requests = &reqs.get_uint32();
    *this->requests = 0;

    auto& err = Statman::get().create(
      Stat::UINT32, blkname() + ".errors");
    this->errors = &err.get_uint32();
    *this->errors = 0;
  }

  uint32_t needed_features =
    FEAT(VIRTIO_BLK_F_BLK_SIZE);
  negotiate_features(needed_features);

  CHECK(features() & FEAT(VIRTIO_BLK_F_BARRIER),
        "Barrier is enabled");
  CHECK(features() & FEAT(VIRTIO_BLK_F_SIZE_MAX),
        "Size-max is known");
  CHECK(features() & FEAT(VIRTIO_BLK_F_SEG_MAX),
        "Seg-max is known");
  CHECK(features() & FEAT(VIRTIO_BLK_F_GEOMETRY),
        "Geometry structure is used");
  CHECK(features() & FEAT(VIRTIO_BLK_F_RO),
        "Device is read-only");
  CHECK(features() & FEAT(VIRTIO_BLK_F_BLK_SIZE),
        "Block-size is known");
  CHECK(features() & FEAT(VIRTIO_BLK_F_SCSI),
        "SCSI is enabled :(");
  CHECK(features() & FEAT(VIRTIO_BLK_F_FLUSH),
        "Flush enabled");

  CHECK ((features() & needed_features) == needed_features,
         "Negotiated needed features");

  // Step 1 - Initialize REQ queue
  auto success = assign_queue(0, (uint32_t) req.queue_desc());
  CHECK(success, "Request queue assigned (0x%x) to device",
        (uint32_t) req.queue_desc());

  // Step 3 - Fill receive queue with buffers
  // DEBUG: Disable
  INFO("VirtioBlk", "Queue size: %i\tRequest size: %u\n",
       req.size(), sizeof(request_t));

  // Get device configuration
  get_config();

  // Signal setup complete.
  setup_complete((features() & needed_features) == needed_features);
  CHECK((features() & needed_features) == needed_features, "Signalled driver OK");

  // Hook up IRQ handler (inherited from Virtio)
  if (is_msix())
  {
    // update IRQ subscriptions
    IRQ_manager::get().subscribe(irq() + 0, {this, &VirtioBlk::service_RX});
    IRQ_manager::get().subscribe(irq() + 1, {this, &VirtioBlk::msix_conf_handler});
  }
  else
  {
    auto del(delegate<void()>{this, &VirtioBlk::irq_handler});
    IRQ_manager::get().subscribe(irq(), del);
  }

  // Done
  INFO("VirtioBlk", "Block device with %llu sectors capacity", config.capacity);
}
Example #2
0
/*------------------------------------------------------------------*/
void pr_out(ADAPTER *a)
{
	byte e_no;
	ENTITY *this = NULL;
	BUFFERS *X;
	word length;
	word i;
	word clength;
	REQ *ReqOut;
	byte more;
	byte ReadyCount;
	byte ReqCount;
	byte Id;
	dtrc(dprintf("pr_out"));
	/* while a request is pending ...                           */
	e_no = look_req(a);
	if (!e_no)
	{
		dtrc(dprintf("no_req"));
		return;
	}
	ReadyCount = pr_ready(a);
	if (!ReadyCount)
	{
		dtrc(dprintf("not_ready"));
		return;
	}
	ReqCount = 0;
	while (e_no && ReadyCount) {
		next_req(a);
		this = entity_ptr(a, e_no);
#ifdef USE_EXTENDED_DEBUGS
		if (!this)
		{
			DBG_FTL(("XDI: [%02x] !A%d ==> NULL entity ptr - try to ignore",
				 xdi_xlog_sec++, (int)((ISDN_ADAPTER *)a->io)->ANum))
				e_no = look_req(a);
			ReadyCount--;
			continue;
		}
		{
			DBG_TRC((">A%d Id=0x%x Req=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, this->Id, this->Req))
				}
#else
		dbug(dprintf("out:Req=%x,Id=%x,Ch=%x", this->Req, this->Id, this->ReqCh));
#endif
		/* get address of next available request buffer             */
		ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)];
#if defined(DIVA_ISTREAM)
		if (!(a->tx_stream[this->Id]   &&
		      this->Req == N_DATA)) {
#endif
			/* now copy the data from the current data buffer into the  */
			/* adapters request buffer                                  */
			length = 0;
			i = this->XCurrent;
			X = PTR_X(a, this);
			while (i < this->XNum && length < 270) {
				clength = min((word)(270 - length), (word)(X[i].PLength-this->XOffset));
				a->ram_out_buffer(a,
						  &ReqOut->XBuffer.P[length],
						  PTR_P(a, this, &X[i].P[this->XOffset]),
						  clength);
				length += clength;
				this->XOffset += clength;
				if (this->XOffset == X[i].PLength) {
					this->XCurrent = (byte)++i;
					this->XOffset = 0;
				}
			}
#if defined(DIVA_ISTREAM)
		} else { /* Use CMA extension in order to transfer data to the card */
			i = this->XCurrent;
			X = PTR_X(a, this);
			while (i < this->XNum) {
				diva_istream_write(a,
						   this->Id,
						   PTR_P(a, this, &X[i].P[0]),
						   X[i].PLength,
						   ((i + 1) == this->XNum),
						   0, 0);
				this->XCurrent = (byte)++i;
			}
			length = 0;
		}
#endif
		a->ram_outw(a, &ReqOut->XBuffer.length, length);
		a->ram_out(a, &ReqOut->ReqId, this->Id);
		a->ram_out(a, &ReqOut->ReqCh, this->ReqCh);
		/* if it's a specific request (no ASSIGN) ...                */
		if (this->Id & 0x1f) {
			/* if buffers are left in the list of data buffers do       */
			/* do chaining (LL_MDATA, N_MDATA)                          */
			this->More++;
			if (i < this->XNum && this->MInd) {
				xdi_xlog_request(XDI_A_NR(a), this->Id, this->ReqCh, this->MInd,
						 a->IdTypeTable[this->No]);
				a->ram_out(a, &ReqOut->Req, this->MInd);
				more = true;
			}
			else {
				xdi_xlog_request(XDI_A_NR(a), this->Id, this->ReqCh, this->Req,
						 a->IdTypeTable[this->No]);
				this->More |= XMOREF;
				a->ram_out(a, &ReqOut->Req, this->Req);
				more = false;
				if (a->FlowControlIdTable[this->ReqCh] == this->Id)
					a->FlowControlSkipTable[this->ReqCh] = true;
				/*
				  Note that remove request was sent to the card
				*/
				if (this->Req == REMOVE) {
					a->misc_flags_table[e_no] |= DIVA_MISC_FLAGS_REMOVE_PENDING;
				}
			}
			/* if we did chaining, this entity is put back into the     */
			/* request queue                                            */
			if (more) {
				req_queue(a, this->No);
			}
		}
		/* else it's a ASSIGN                                       */
		else {
			/* save the request code used for buffer chaining           */
			this->MInd = 0;
			if (this->Id == BLLC_ID) this->MInd = LL_MDATA;
			if (this->Id == NL_ID ||
			    this->Id == TASK_ID ||
			    this->Id == MAN_ID
				) this->MInd = N_MDATA;
			/* send the ASSIGN                                          */
			a->IdTypeTable[this->No] = this->Id;
			xdi_xlog_request(XDI_A_NR(a), this->Id, this->ReqCh, this->Req, this->Id);
			this->More |= XMOREF;
			a->ram_out(a, &ReqOut->Req, this->Req);
			/* save the reference of the ASSIGN                         */
			assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference));
		}
		a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next));
		ReadyCount--;
		ReqCount++;
		e_no = look_req(a);
	}
	/* send the filled request buffers to the ISDN adapter      */
	a->ram_out(a, &PR_RAM->ReqInput,
		   (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount));
	/* if it is a 'unreturncoded' UREMOVE request, remove the  */
	/* Id from our table after sending the request             */
	if (this && (this->Req == UREMOVE) && this->Id) {
		Id = this->Id;
		e_no = a->IdTable[Id];
		free_entity(a, e_no);
		for (i = 0; i < 256; i++)
		{
			if (a->FlowControlIdTable[i] == Id)
				a->FlowControlIdTable[i] = 0;
		}
		a->IdTable[Id] = 0;
		this->Id = 0;
	}
}
Example #3
0
void DivasOut(ADAPTER * a)
{
  byte e_no;
  ENTITY  * this = NULL;
  BUFFERS  *X;
  word length;
  word i;
  word clength;
  REQ * ReqOut;
  byte more;
  byte ReadyCount;
  byte ReqCount;
  byte Id;

        /* while a request is pending ...                           */
  e_no = look_req(a);
  if(!e_no)
  {
    return;
  }

  ReadyCount = pr_ready(a);
  if(!ReadyCount)
  {
    DPRINTF(("IDI: card not ready for next request"));
    return;
  }

  ReqCount = 0;
  while(e_no && ReadyCount) {

    next_req(a);

    this = entity_ptr(a, e_no);

#ifdef	USE_EXTENDED_DEBUGS
	if ( !this )
	{
		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
		DBG_FTL(("!A%d ==> NULL entity ptr - try to ignore", (int)io->ANum))
		e_no = look_req(a) ;
		ReadyCount-- ;
		continue ;
	}
	{
		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
		DPRINTF(("IDI: >A%d Id=0x%x Req=0x%x", io->ANum, this->Id, this->Req))
	}
#else
    DPRINTF(("IDI: >REQ=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh));
#endif

        /* get address of next available request buffer             */
    ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)];

        /* now copy the data from the current data buffer into the  */
        /* adapters request buffer                                  */
    length = 0;
    i = this->XCurrent;
    X = PTR_X(a,this);
    while(i<this->XNum && length<270) {
      clength = (word)(270-length);
      if (clength > X[i].PLength-this->XOffset)
	      clength = X[i].PLength-this->XOffset;
      a->ram_out_buffer(a,
                        &ReqOut->XBuffer.P[length],
                        PTR_P(a,this,&X[i].P[this->XOffset]),
                        clength);

      length +=clength;
      this->XOffset +=clength;
      if(this->XOffset==X[i].PLength) {
        this->XCurrent = (byte)++i;
        this->XOffset = 0;
      }
    }

    a->ram_outw(a, &ReqOut->XBuffer.length, length);
    a->ram_out(a, &ReqOut->ReqId, this->Id);
    a->ram_out(a, &ReqOut->ReqCh, this->ReqCh);

        /* if its a specific request (no ASSIGN) ...                */

    if(this->Id &0x1f) {

        /* if buffers are left in the list of data buffers do       */
        /* do chaining (LL_MDATA, N_MDATA)                          */

      this->More++;
      if(i<this->XNum && this->MInd) {
        a->ram_out(a, &ReqOut->Req, this->MInd);
        more = TRUE;
      }
      else {
        this->More |=XMOREF;
        a->ram_out(a, &ReqOut->Req, this->Req);
        more = FALSE;
      }

        /* if we did chaining, this entity is put back into the     */
        /* request queue                                            */

      if(more) {
        req_queue(a,this->No);
      }
    }

        /* else it's a ASSIGN                                       */

    else {

        /* save the request code used for buffer chaining           */

      this->MInd = 0;
      if (this->Id==BLLC_ID) this->MInd = LL_MDATA;
      if (this->Id==NL_ID   ||
          this->Id==TASK_ID ||
          this->Id==MAN_ID
        ) this->MInd = N_MDATA;

        /* send the ASSIGN                                          */

      this->More |=XMOREF;
      a->ram_out(a, &ReqOut->Req, this->Req);

        /* save the reference of the ASSIGN                         */

      assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference));
    }
    a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next));
    ReadyCount--;
    ReqCount++;

    e_no = look_req(a);
  }

        /* send the filled request buffers to the ISDN adapter      */

  a->ram_out(a, &PR_RAM->ReqInput,
             (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount));

        /* if it is a 'unreturncoded' UREMOVE request, remove the  */
        /* Id from our table after sending the request             */
  if(this->Req==UREMOVE && this->Id) {
    Id = this->Id;
    e_no = a->IdTable[Id];
    free_entity(a, e_no);
    a->IdTable[Id] = 0;
    this->Id = 0;
  }

}