예제 #1
0
파일: ida.c 프로젝트: AhmadTux/DragonFlyBSD
void
ida_submit_buf(struct ida_softc *ida, struct bio *bio)
{
        bioqdisksort(&ida->bio_queue, bio);
        ida_construct_qcb(ida);
	ida_start(ida);
}
예제 #2
0
static void
ida_data_cb(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
{
	struct ida_hardware_qcb *hwqcb;
	struct ida_softc *ida;
	struct ida_qcb *qcb;
	bus_dmasync_op_t op;
	int i;

	qcb = arg;
	ida = qcb->ida;
	if (!dumping)
		mtx_assert(&ida->lock, MA_OWNED);
	if (error) {
		qcb->error = error;
		ida_done(ida, qcb);
		return;
	}

	hwqcb = qcb->hwqcb;
	hwqcb->hdr.size = htole16((sizeof(struct ida_req) +
	    sizeof(struct ida_sgb) * IDA_NSEG) >> 2);

	for (i = 0; i < nsegments; i++) {
		hwqcb->seg[i].addr = htole32(segs[i].ds_addr);
		hwqcb->seg[i].length = htole32(segs[i].ds_len);
	}
	hwqcb->req.sgcount = nsegments;
	if (qcb->flags & DMA_DATA_TRANSFER) {
		switch (qcb->flags & DMA_DATA_TRANSFER) {
		case DMA_DATA_TRANSFER:
			op = BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE;
			break;
		case DMA_DATA_IN:
			op = BUS_DMASYNC_PREREAD;
			break;
		default:
			KASSERT((qcb->flags & DMA_DATA_TRANSFER) ==
			    DMA_DATA_OUT, ("bad DMA data flags"));
			op = BUS_DMASYNC_PREWRITE;
			break;
		}
		bus_dmamap_sync(ida->buffer_dmat, qcb->dmamap, op);
	}
	bus_dmamap_sync(ida->hwqcb_dmat, ida->hwqcb_dmamap,
	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);

	STAILQ_INSERT_TAIL(&ida->qcb_queue, qcb, link.stqe);
	ida_start(ida);
	ida->flags &= ~IDA_QFROZEN;
}
예제 #3
0
파일: ida.c 프로젝트: AhmadTux/DragonFlyBSD
int
ida_command(struct ida_softc *ida, int command, void *data, int datasize,
	int drive, u_int64_t pblkno, int flags)
{
	struct ida_hardware_qcb *hwqcb;
	struct ida_qcb *qcb;
	bus_dmasync_op_t op;
	int error;

	crit_enter();
	qcb = ida_get_qcb(ida);
	crit_exit();

	if (qcb == NULL) {
		kprintf("ida_command: out of QCBs");
		return (EAGAIN);
	}

	hwqcb = qcb->hwqcb;
	bzero(hwqcb, sizeof(struct ida_hdr) + sizeof(struct ida_req));

	bus_dmamap_load(ida->buffer_dmat, qcb->dmamap,
	    data, datasize, ida_setup_dmamap, hwqcb, 0);
	op = qcb->flags & DMA_DATA_IN ?
	    BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE;
	bus_dmamap_sync(ida->buffer_dmat, qcb->dmamap, op);

	hwqcb->hdr.drive = drive;
	hwqcb->req.blkno = pblkno;
	hwqcb->req.bcount = howmany(datasize, DEV_BSIZE);
	hwqcb->req.command = command;

	KKASSERT(pblkno < 0x100000000ULL);

	qcb->flags = flags | IDA_COMMAND;

	crit_enter();
	STAILQ_INSERT_TAIL(&ida->qcb_queue, qcb, link.stqe);
	ida_start(ida);
	error = ida_wait(ida, qcb);
	crit_exit();

	/* XXX should have status returned here? */
	/* XXX have "status pointer" area in QCB? */

	return (error);
}
예제 #4
0
파일: ida.c 프로젝트: AhmadTux/DragonFlyBSD
void
ida_intr(void *data)
{
	struct ida_softc *ida;
	struct ida_qcb *qcb;
	bus_addr_t completed;

	ida = (struct ida_softc *)data;

	if (ida->cmd.int_pending(ida) == 0)
		return;				/* not our interrupt */

	while ((completed = ida->cmd.done(ida)) != 0) {
		qcb = idahwqcbptov(ida, completed & ~3);

		if (qcb == NULL || qcb->state != QCB_ACTIVE) {
			device_printf(ida->dev,
			    "ignoring completion %jx\n", (uintmax_t)completed);
			continue;
		}
		ida_done(ida, qcb);
	}
	ida_start(ida);
}
예제 #5
0
파일: ida.c 프로젝트: UnitedMarsupials/kame
/* Read/write routine for a buffer.  Finds the proper unit, range checks
 * arguments, and schedules the transfer.  Does not wait for the transfer
 * to complete.  Multi-page transfers are supported.  All I/O requests must
 * be a multiple of a sector in length.
 */
void
idstrategy(struct buf *bp)
{
  int unit = dkunit(bp->b_dev);
  struct ida_drv *drv;
  int opri;

  if (unit >= NID) {
    printf("ida: unit out of range\n");
    bp->b_error = EINVAL;
    goto bad;
  }

  if (!(drv = id_drive[unit]) || !(drv->flags & ID_INIT)) {
    printf("id%d: drive not initialised\n", unit);
    bp->b_error = EINVAL;
    goto bad;
  }

  if (bp->b_blkno < 0) {
    printf("id%d: negative block requested\n", unit);
    bp->b_error = EINVAL;
    goto bad;
  }

  if (bp->b_bcount % DEV_BSIZE != 0) { /* bounds check */
    printf("id%d: count (%lu) not a multiple of a block\n",
	   unit, bp->b_bcount);
    bp->b_error = EINVAL;
    goto bad;
  }

  idaminphys(bp); /* adjust the transfer size */

  /* "soft" write protect check */
  if ((drv->flags & ID_WRITEPROT) && (bp->b_flags & B_READ) == 0) {
    bp->b_error = EROFS;
    goto bad;
  }

  /* If it's a null transfer, return immediately */
  if (bp->b_bcount == 0) {
    goto done;
  }

  if (dscheck(bp, drv->slices) <= 0) {
    goto done;
  }
   
  opri = splbio();
  ida_queue_buf(unit, bp);
  devstat_start_transaction(&drv->dk_stats);
  ida_start(drv->ctl_unit); /* hit the appropriate controller */
  splx(opri);

  return /*0*/;

bad:
  bp->b_flags |= B_ERROR;
 
done:
  /* correctly set the buf to indicate a completed xfer */
  bp->b_resid = bp->b_bcount;
  biodone(bp);
  return /*0*/;
}