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); }
static void ida_construct_qcb(struct ida_softc *ida) { struct ida_hardware_qcb *hwqcb; struct ida_qcb *qcb; bus_dmasync_op_t op; struct buf *bp; struct bio *bio; bio = bioq_first(&ida->bio_queue); if (bio == NULL) return; /* no more buffers */ qcb = ida_get_qcb(ida); if (qcb == NULL) return; /* out of resources */ bioq_remove(&ida->bio_queue, bio); qcb->bio = bio; qcb->flags = 0; hwqcb = qcb->hwqcb; bzero(hwqcb, sizeof(struct ida_hdr) + sizeof(struct ida_req)); bp = bio->bio_buf; bus_dmamap_load(ida->buffer_dmat, qcb->dmamap, (void *)bp->b_data, bp->b_bcount, 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); { struct idad_softc *drv; drv = (struct idad_softc *)bio->bio_driver_info; hwqcb->hdr.drive = drv->drive; } hwqcb->req.blkno = bio->bio_offset >> DEV_BSHIFT; hwqcb->req.bcount = howmany(bp->b_bcount, DEV_BSIZE); hwqcb->req.command = (bp->b_cmd == BUF_CMD_READ) ? CMD_READ : CMD_WRITE; KKASSERT(bio->bio_offset < 0x100000000ULL * DEV_BSIZE); STAILQ_INSERT_TAIL(&ida->qcb_queue, qcb, link.stqe); }
static void ida_startio(struct ida_softc *ida) { struct ida_hardware_qcb *hwqcb; struct ida_qcb *qcb; struct idad_softc *drv; struct bio *bp; int error; mtx_assert(&ida->lock, MA_OWNED); for (;;) { if (ida->flags & IDA_QFROZEN) return; bp = bioq_first(&ida->bio_queue); if (bp == NULL) return; /* no more buffers */ qcb = ida_get_qcb(ida); if (qcb == NULL) return; /* out of resources */ bioq_remove(&ida->bio_queue, bp); qcb->buf = bp; qcb->flags = bp->bio_cmd == BIO_READ ? DMA_DATA_IN : DMA_DATA_OUT; hwqcb = qcb->hwqcb; drv = bp->bio_driver1; hwqcb->hdr.drive = drv->drive; hwqcb->req.blkno = bp->bio_pblkno; hwqcb->req.bcount = howmany(bp->bio_bcount, DEV_BSIZE); hwqcb->req.command = bp->bio_cmd == BIO_READ ? CMD_READ : CMD_WRITE; error = ida_map_qcb(ida, qcb, bp->bio_data, bp->bio_bcount); if (error) { qcb->error = error; ida_done(ida, qcb); } } }
int ida_command(struct ida_softc *ida, int command, void *data, int datasize, int drive, u_int32_t pblkno, int flags) { struct ida_hardware_qcb *hwqcb; struct ida_qcb *qcb; int error; if (!dumping) mtx_assert(&ida->lock, MA_OWNED); qcb = ida_get_qcb(ida); if (qcb == NULL) { device_printf(ida->dev, "out of QCBs\n"); return (EAGAIN); } qcb->flags = flags | IDA_COMMAND; hwqcb = qcb->hwqcb; hwqcb->hdr.drive = drive; hwqcb->req.blkno = htole32(pblkno); hwqcb->req.bcount = htole16(howmany(datasize, DEV_BSIZE)); hwqcb->req.command = command; error = ida_map_qcb(ida, qcb, data, datasize); if (error == 0) { error = ida_wait(ida, qcb); /* Don't free QCB on a timeout in case it later completes. */ if (error) return (error); error = qcb->error; } /* XXX should have status returned here? */ /* XXX have "status pointer" area in QCB? */ ida_free_qcb(ida, qcb); return (error); }