static int dk_translate(struct dk_softc *dksc, struct buf *bp) { int part; int wlabel; daddr_t blkno; struct disklabel *lp; struct disk *dk; uint64_t numsecs; unsigned secsize; lp = dksc->sc_dkdev.dk_label; dk = &dksc->sc_dkdev; part = DISKPART(bp->b_dev); numsecs = dk->dk_geom.dg_secperunit; secsize = dk->dk_geom.dg_secsize; /* * The transfer must be a whole number of blocks and the offset must * not be negative. */ if ((bp->b_bcount % secsize) != 0 || bp->b_blkno < 0) { bp->b_error = EINVAL; goto done; } /* If there is nothing to do, then we are done */ if (bp->b_bcount == 0) goto done; wlabel = dksc->sc_flags & (DKF_WLABEL|DKF_LABELLING); if (part == RAW_PART) { uint64_t numblocks = btodb(numsecs * secsize); if (bounds_check_with_mediasize(bp, DEV_BSIZE, numblocks) <= 0) goto done; } else { if (bounds_check_with_label(&dksc->sc_dkdev, bp, wlabel) <= 0) goto done; } /* * Convert the block number to absolute and put it in terms * of the device's logical block size. */ if (secsize >= DEV_BSIZE) blkno = bp->b_blkno / (secsize / DEV_BSIZE); else blkno = bp->b_blkno * (DEV_BSIZE / secsize); if (part != RAW_PART) blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset; bp->b_rawblkno = blkno; return -1; done: bp->b_resid = bp->b_bcount; return bp->b_error; }
void flashstrategy(struct buf * const bp) { struct flash_softc *sc; const struct flash_interface *flash_if; const struct flash_partition *part; int unit, device_blks; unit = minor(bp->b_dev); sc = device_lookup_private(&flash_cd, unit); if (sc == NULL) { bp->b_error = ENXIO; goto done; } flash_if = sc->flash_if; part = &sc->sc_partinfo; /* divider */ KASSERT(flash_if->writesize != 0); aprint_debug_dev(sc->sc_dev, "flash_strategy()\n"); if (!(bp->b_flags & B_READ) && sc->sc_readonly) { bp->b_error = EACCES; goto done; } /* check if length is not negative */ if (bp->b_blkno < 0) { bp->b_error = EINVAL; goto done; } /* zero lenght i/o */ if (bp->b_bcount == 0) { goto done; } device_blks = sc->sc_partinfo.part_size / DEV_BSIZE; KASSERT(part->part_offset % DEV_BSIZE == 0); bp->b_rawblkno = bp->b_blkno + (part->part_offset / DEV_BSIZE); if (bounds_check_with_mediasize(bp, DEV_BSIZE, device_blks) <= 0) { goto done; } bp->b_resid = bp->b_bcount; flash_if->submit(sc->sc_parent_dev, bp); return; done: bp->b_resid = bp->b_bcount; biodone(bp); }
/* * Do all IO operations on dm logical devices. */ static int dmstrategy(struct dev_strategy_args *ap) { cdev_t dev = ap->a_head.a_dev; struct bio *bio = ap->a_bio; struct buf *bp = bio->bio_buf; int bypass; dm_dev_t *dmv; dm_table_t *tbl; dm_table_entry_t *table_en; struct buf *nestbuf; uint32_t dev_type; uint64_t buf_start, buf_len, issued_len; uint64_t table_start, table_end; uint64_t start, end; buf_start = bio->bio_offset; buf_len = bp->b_bcount; tbl = NULL; table_end = 0; dev_type = 0; issued_len = 0; dmv = dev->si_drv1; switch(bp->b_cmd) { case BUF_CMD_READ: case BUF_CMD_WRITE: case BUF_CMD_FREEBLKS: bypass = 0; break; case BUF_CMD_FLUSH: bypass = 1; KKASSERT(buf_len == 0); break; default: bp->b_error = EIO; bp->b_resid = bp->b_bcount; biodone(bio); return 0; } if (bypass == 0 && bounds_check_with_mediasize(bio, DEV_BSIZE, dm_table_size(&dmv->table_head)) <= 0) { bp->b_resid = bp->b_bcount; biodone(bio); return 0; } /* Select active table */ tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE); nestiobuf_init(bio); devstat_start_transaction(&dmv->stats); /* * Find out what tables I want to select. */ SLIST_FOREACH(table_en, tbl, next) { /* * I need need number of bytes not blocks. */ table_start = table_en->start * DEV_BSIZE; table_end = table_start + (table_en->length) * DEV_BSIZE; /* * Calculate the start and end */ start = MAX(table_start, buf_start); end = MIN(table_end, buf_start + buf_len); aprint_debug("----------------------------------------\n"); aprint_debug("table_start %010" PRIu64", table_end %010" PRIu64 "\n", table_start, table_end); aprint_debug("buf_start %010" PRIu64", buf_len %010" PRIu64"\n", buf_start, buf_len); aprint_debug("start-buf_start %010"PRIu64", end %010" PRIu64"\n", start - buf_start, end); aprint_debug("start %010" PRIu64" , end %010" PRIu64"\n", start, end); aprint_debug("\n----------------------------------------\n"); if (bypass) { nestbuf = getpbuf(NULL); nestbuf->b_flags |= bio->bio_buf->b_flags & B_HASBOGUS; nestiobuf_add(bio, nestbuf, 0, 0, &dmv->stats); nestbuf->b_bio1.bio_offset = 0; table_en->target->strategy(table_en, nestbuf); } else if (start < end) { nestbuf = getpbuf(NULL); nestbuf->b_flags |= bio->bio_buf->b_flags & B_HASBOGUS; nestiobuf_add(bio, nestbuf, start - buf_start, (end - start), &dmv->stats); issued_len += end - start; nestbuf->b_bio1.bio_offset = (start - table_start); table_en->target->strategy(table_en, nestbuf); } }
/* * Queue the request, and wakeup the kernel thread to handle it. */ static void vndstrategy(struct buf *bp) { int unit = vndunit(bp->b_dev); struct vnd_softc *vnd = device_lookup_private(&vnd_cd, unit); struct disklabel *lp; daddr_t blkno; int s = splbio(); if (vnd == NULL) { bp->b_error = ENXIO; goto done; } lp = vnd->sc_dkdev.dk_label; if ((vnd->sc_flags & VNF_INITED) == 0) { bp->b_error = ENXIO; goto done; } /* * The transfer must be a whole number of blocks. */ if ((bp->b_bcount % lp->d_secsize) != 0) { bp->b_error = EINVAL; goto done; } /* * check if we're read-only. */ if ((vnd->sc_flags & VNF_READONLY) && !(bp->b_flags & B_READ)) { bp->b_error = EACCES; goto done; } /* If it's a nil transfer, wake up the top half now. */ if (bp->b_bcount == 0) { goto done; } /* * Do bounds checking and adjust transfer. If there's an error, * the bounds check will flag that for us. */ if (DISKPART(bp->b_dev) == RAW_PART) { if (bounds_check_with_mediasize(bp, DEV_BSIZE, vnd->sc_size) <= 0) goto done; } else { if (bounds_check_with_label(&vnd->sc_dkdev, bp, vnd->sc_flags & (VNF_WLABEL|VNF_LABELLING)) <= 0) goto done; } /* * Put the block number in terms of the logical blocksize * of the "device". */ blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); /* * Translate the partition-relative block number to an absolute. */ if (DISKPART(bp->b_dev) != RAW_PART) { struct partition *pp; pp = &vnd->sc_dkdev.dk_label->d_partitions[ DISKPART(bp->b_dev)]; blkno += pp->p_offset; } bp->b_rawblkno = blkno; #ifdef DEBUG if (vnddebug & VDB_FOLLOW) printf("vndstrategy(%p): unit %d\n", bp, unit); #endif if ((vnd->sc_flags & VNF_USE_VN_RDWR)) { KASSERT(vnd->sc_pending >= 0 && vnd->sc_pending <= VND_MAXPENDING(vnd)); while (vnd->sc_pending == VND_MAXPENDING(vnd)) tsleep(&vnd->sc_pending, PRIBIO, "vndpc", 0); vnd->sc_pending++; } bufq_put(vnd->sc_tab, bp); wakeup(&vnd->sc_tab); splx(s); return; done: bp->b_resid = bp->b_bcount; biodone(bp); splx(s); }