void ida_submit_buf(struct ida_softc *ida, struct bio *bio) { bioqdisksort(&ida->bio_queue, bio); ida_construct_qcb(ida); ida_start(ida); }
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; }
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); }
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); }
/* 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*/; }