Exemplo n.º 1
0
/* ARGSUSED */
static	int
vnioctl(struct dev_ioctl_args *ap)
{
	cdev_t dev = ap->a_head.a_dev;
	struct vn_softc *vn;
	struct vn_ioctl *vio;
	int error;
	u_long *f;

	vn = dev->si_drv1;
	IFOPT(vn,VN_FOLLOW) {
		kprintf("vnioctl(%s, 0x%lx, %p, 0x%x): unit %d\n",
		    devtoname(dev), ap->a_cmd, ap->a_data, ap->a_fflag,
		    dkunit(dev));
	}
Exemplo n.º 2
0
static void
vninitvn(struct vn_softc *vn, cdev_t dev)
{
	int unit;

	KKASSERT(vn != NULL);
	KKASSERT(dev != NULL);
	unit = dkunit(dev);

	vn->sc_unit = unit;
	dev->si_drv1 = vn;
	vn->sc_dev = dev;

	SLIST_INSERT_HEAD(&vn_list, vn, sc_list);
}
Exemplo n.º 3
0
/* ARGSUSED */
int
idclose(dev_t dev, int flags, int fmt, struct proc *p)
{
  struct ida_drv *drv;
  int	part = dkpart(dev);
  int unit = dkunit(dev);

  if (unit >= NID || part >= MAXPARTITIONS) /* bounds check */
    return(ENXIO);

  drv = id_drive[unit];
  dsclose(dev, fmt, drv->slices);
  if (!dsisopen(drv->slices)) {
    drv->flags &= ~ID_DEV_OPEN;
  }
  return 0;
}
Exemplo n.º 4
0
Arquivo: hd.c Projeto: jamjr/Helios-NG
/*
 * This returns the size of the passed device in number of 512 blocks (?)
 */
int hd_size(dev_t dev)
{
	u_int major = major(dev);
	u_int unit = dkunit(dev);
	u_int part = dkpart(dev);
	struct disk *du;
	int val;

	if (unit >= MAXDISKS) return(-1);
	du = &hd[major].disk[unit];
	if (du->dk_state == CLOSED) {
		val = hd_open(dev,0,0);
		if (val < 0) return(-1);
	}
	return((int)((u_long)du->dk_lab.d_partitions[part].p_size *
		du->dk_lab.d_secsize / 512));
}
Exemplo n.º 5
0
/*
 * Initialize a drive.
 */
int
idopen(dev_t dev, int flags, int fmt, struct proc *p)
{
  struct ida_drv *drv;
  int part = dkpart(dev);
  int unit = dkunit(dev);
  struct disklabel label;
  int err;

  if (unit >= NID || part >= MAXPARTITIONS) /* bounds check */
    return(ENXIO);

  drv = id_drive[unit];
  if (!drv || !(drv->flags & ID_INIT)) /* drive not initialised */
    return(ENXIO);

  drv->flags |= ID_DEV_OPEN;

  /* knock up a label for the whole disk. */
  bzero(&label, sizeof label);
  label.d_secsize = u_unpack(drv->drv_info.secsize);
  label.d_nsectors = u_unpack(drv->drv_info.nsectors);
  label.d_ntracks = u_unpack(drv->drv_info.ntracks);
  label.d_ncylinders = u_unpack(drv->drv_info.ncylinders);
  label.d_secpercyl =
    u_unpack(drv->drv_info.ntracks) * u_unpack(drv->drv_info.nsectors);
  if (label.d_secpercyl == 0)
    label.d_secpercyl = 100; /* prevent accidental division by zero */
  label.d_secperunit = u_unpack(drv->drv_info.secperunit);

  /* Initialize slice tables. */
  if ((err = dsopen("id", dev, fmt, 0, &drv->slices, &label, idstrategy,
		    (ds_setgeom_t *)NULL, &id_cdevsw)) == NULL) {
    return 0;
  }

  if (!dsisopen(drv->slices)) {
    drv->flags &= ~ID_DEV_OPEN;
  }
  return err;
}
Exemplo n.º 6
0
static	int
vnclose(struct dev_close_args *ap)
{
	cdev_t dev = ap->a_head.a_dev;
	struct vn_softc *vn;

	vn = dev->si_drv1;
	KKASSERT(vn != NULL);

	vn->sc_flags &= ~VNF_OPENED;

	/* The disk has been detached and can now be safely destroyed */
	if (vn->sc_flags & VNF_DESTROY) {
		KKASSERT(disk_getopencount(&vn->sc_disk) == 0);
		disk_destroy(&vn->sc_disk);
		devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(vn), dkunit(dev));
		SLIST_REMOVE(&vn_list, vn, vn_softc, sc_list);
		kfree(vn, M_VN);
	}
	return (0);
}
Exemplo n.º 7
0
int
idioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
{
  struct ida_drv *drv;
  int part = dkpart(dev);
  int unit = dkunit(dev);
  int err;

  if (unit >= NID || part >= MAXPARTITIONS ||
      !(drv = id_drive[unit]) || !(drv->flags & ID_INIT)) /* sanity check */
    return(ENXIO);

  err = dsioctl("id", dev, cmd, addr, flag, &drv->slices,
		idstrategy, (ds_setgeom_t *)NULL);

  if (err != -1)
    return (err);

  if (dkpart(dev) != RAW_PART)
    return (ENOTTY);

  return (0);
}
Exemplo n.º 8
0
static
void
mbr_extended(cdev_t dev, struct disk_info *info, struct diskslices *ssp,
	    u_int64_t ext_offset, u_int64_t ext_size, u_int64_t base_ext_offset,
	    int nsectors, int ntracks, u_int64_t mbr_offset, int level)
{
	struct buf *bp;
	u_char	*cp;
	int	dospart;
	struct dos_partition *dp;
	struct dos_partition dpcopy[NDOSPART];
	u_int64_t ext_offsets[NDOSPART];
	u_int64_t ext_sizes[NDOSPART];
	char	partname[2];
	int	slice;
	char	*sname;
	struct diskslice *sp;

	if (level >= 16) {
		kprintf(
	"%s: excessive recursion in search for slices; aborting search\n",
		       devtoname(dev));
		return;
	}

	/* Read extended boot record. */
	bp = geteblk((int)info->d_media_blksize);
	bp->b_bio1.bio_offset = (off_t)ext_offset * info->d_media_blksize;
	bp->b_bio1.bio_done = biodone_sync;
	bp->b_bio1.bio_flags |= BIO_SYNC;
	bp->b_bcount = info->d_media_blksize;
	bp->b_cmd = BUF_CMD_READ;
	bp->b_flags |= B_FAILONDIS;
	dev_dstrategy(dev, &bp->b_bio1);
	if (biowait(&bp->b_bio1, "mbrrd") != 0) {
		diskerr(&bp->b_bio1, dev,
			"reading extended partition table: error",
			LOG_PRINTF, 0);
		kprintf("\n");
		goto done;
	}

	/* Weakly verify it. */
	cp = bp->b_data;
	if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) {
		sname = dsname(dev, dkunit(dev), WHOLE_DISK_SLICE, WHOLE_SLICE_PART,
			       partname);
		if (bootverbose)
			kprintf("%s: invalid extended partition table: no magic\n",
			       sname);
		goto done;
	}

	/* Make a copy of the partition table to avoid alignment problems. */
	memcpy(&dpcopy[0], cp + DOSPARTOFF, sizeof(dpcopy));

	slice = ssp->dss_nslices;
	for (dospart = 0, dp = &dpcopy[0]; dospart < NDOSPART;
	    dospart++, dp++) {
		ext_sizes[dospart] = 0;
		if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0
		    && dp->dp_start == 0 && dp->dp_size == 0)
			continue;
		if (dp->dp_typ == DOSPTYP_EXTENDED ||
		    dp->dp_typ == DOSPTYP_EXTENDEDX) {
			static char buf[32];

			sname = dsname(dev, dkunit(dev), WHOLE_DISK_SLICE,
				       WHOLE_SLICE_PART, partname);
			ksnprintf(buf, sizeof(buf), "%s", sname);
			if (strlen(buf) < sizeof buf - 11)
				strcat(buf, "<extended>");
			check_part(buf, dp, base_ext_offset, nsectors,
				   ntracks, mbr_offset);
			ext_offsets[dospart] = base_ext_offset + dp->dp_start;
			ext_sizes[dospart] = dp->dp_size;
		} else {
			sname = dsname(dev, dkunit(dev), slice, WHOLE_SLICE_PART,
				       partname);
			check_part(sname, dp, ext_offset, nsectors, ntracks,
				   mbr_offset);
			if (slice >= MAX_SLICES) {
				kprintf("%s: too many slices\n", sname);
				slice++;
				continue;
			}
			sp = &ssp->dss_slices[slice];
			if (mbr_setslice(sname, info, sp, dp, ext_offset) != 0)
				continue;
			slice++;
		}
	}
	ssp->dss_nslices = slice;

	/* If we found any more slices, recursively find all the subslices. */
	for (dospart = 0; dospart < NDOSPART; dospart++) {
		if (ext_sizes[dospart] != 0) {
			mbr_extended(dev, info, ssp, ext_offsets[dospart],
				     ext_sizes[dospart], base_ext_offset,
				     nsectors, ntracks, mbr_offset, ++level);
		}
	}

done:
	bp->b_flags |= B_INVAL | B_AGE;
	brelse(bp);
}
Exemplo n.º 9
0
/*
 * Handle GPT on raw disk.  Note that GPTs are not recursive.  The MBR is
 * ignored once a GPT has been detected.
 *
 * GPTs always start at block #1, regardless of how the MBR has been set up.
 * In fact, the MBR's starting block might be pointing to the boot partition
 * in the GPT rather then to the start of the GPT.
 *
 * This routine is called from mbrinit() when a GPT has been detected.
 */
int
gptinit(cdev_t dev, struct disk_info *info, struct diskslices **sspp)
{
	struct buf *bp1 = NULL;
	struct buf *bp2 = NULL;
	struct gpt_hdr *gpt;
	struct gpt_ent *ent;
	struct diskslice *sp;
	struct diskslices *ssp;
	cdev_t wdev;
	int error;
	uint32_t len;
	uint32_t entries;
	uint32_t entsz;
	uint32_t crc;
	uint32_t table_lba;
	uint32_t table_blocks;
	int i = 0, j;
	const char *dname;

	/*
	 * The GPT starts in sector 1.
	 */
	wdev = dev;
	dname = dev_dname(wdev);
	bp1 = geteblk((int)info->d_media_blksize);
	bp1->b_bio1.bio_offset = info->d_media_blksize;
	bp1->b_bio1.bio_done = biodone_sync;
	bp1->b_bio1.bio_flags |= BIO_SYNC;
	bp1->b_bcount = info->d_media_blksize;
	bp1->b_cmd = BUF_CMD_READ;
	dev_dstrategy(wdev, &bp1->b_bio1);
	if (biowait(&bp1->b_bio1, "gptrd") != 0) {
		kprintf("%s: reading GPT @ block 1: error %d\n",
			dname, bp1->b_error);
		error = EIO;
		goto done;
	}

	/*
	 * Header sanity check
	 */
	gpt = (void *)bp1->b_data;
	len = le32toh(gpt->hdr_size);
	if (len < GPT_MIN_HDR_SIZE || len > info->d_media_blksize) {
		kprintf("%s: Illegal GPT header size %d\n", dname, len);
		error = EINVAL;
		goto done;
	}

	crc = le32toh(gpt->hdr_crc_self);
	gpt->hdr_crc_self = 0;
	if (crc32(gpt, len) != crc) {
		kprintf("%s: GPT CRC32 did not match\n", dname);
		error = EINVAL;
		goto done;
	}

	/*
	 * Validate the partition table and its location, then read it
	 * into a buffer.
	 */
	entries = le32toh(gpt->hdr_entries);
	entsz = le32toh(gpt->hdr_entsz);
	table_lba = le32toh(gpt->hdr_lba_table);
	table_blocks = (entries * entsz + info->d_media_blksize - 1) /
		       info->d_media_blksize;
	if (entries < 1 || entries > 128 ||
	    entsz < 128 || (entsz & 7) || entsz > MAXBSIZE / entries ||
	    table_lba < 2 || table_lba + table_blocks > info->d_media_blocks) {
		kprintf("%s: GPT partition table is out of bounds\n", dname);
		error = EINVAL;
		goto done;
	}

	/*
	 * XXX subject to device dma size limitations
	 */
	bp2 = geteblk((int)(table_blocks * info->d_media_blksize));
	bp2->b_bio1.bio_offset = (off_t)table_lba * info->d_media_blksize;
	bp2->b_bio1.bio_done = biodone_sync;
	bp2->b_bio1.bio_flags |= BIO_SYNC;
	bp2->b_bcount = table_blocks * info->d_media_blksize;
	bp2->b_cmd = BUF_CMD_READ;
	dev_dstrategy(wdev, &bp2->b_bio1);
	if (biowait(&bp2->b_bio1, "gptrd") != 0) {
		kprintf("%s: reading GPT partition table @ %lld: error %d\n",
			dname,
			(long long)bp2->b_bio1.bio_offset,
			bp2->b_error);
		error = EIO;
		goto done;
	}

	/*
	 * We are passed a pointer to a minimal slices struct.  Replace
	 * it with a maximal one (128 slices + special slices).  Well,
	 * really there is only one special slice (the WHOLE_DISK_SLICE)
	 * since we use the compatibility slice for s0, but don't quibble.
	 * 
	 */
	kfree(*sspp, M_DEVBUF);
	ssp = *sspp = dsmakeslicestruct(BASE_SLICE+128, info);

	/*
	 * Create a slice for each partition.
	 */
	for (i = 0; i < (int)entries && i < 128; ++i) {
		struct gpt_ent sent;
		char partname[2];
		char *sname;

		ent = (void *)((char *)bp2->b_data + i * entsz);
		le_uuid_dec(&ent->ent_type, &sent.ent_type);
		le_uuid_dec(&ent->ent_uuid, &sent.ent_uuid);
		sent.ent_lba_start = le64toh(ent->ent_lba_start);
		sent.ent_lba_end = le64toh(ent->ent_lba_end);
		sent.ent_attr = le64toh(ent->ent_attr);

		for (j = 0; j < NELEM(ent->ent_name); ++j)
			sent.ent_name[j] = le16toh(ent->ent_name[j]);

		/*
		 * The COMPATIBILITY_SLICE is actually slice 0 (s0).  This
		 * is a bit weird becaue the whole-disk slice is #1, so
		 * slice 1 (s1) starts at BASE_SLICE.
		 */
		if (i == 0)
			sp = &ssp->dss_slices[COMPATIBILITY_SLICE];
		else
			sp = &ssp->dss_slices[BASE_SLICE+i-1];
		sname = dsname(dev, dkunit(dev), WHOLE_DISK_SLICE,
			       WHOLE_SLICE_PART, partname);

		if (kuuid_is_nil(&sent.ent_type))
			continue;

		if (sent.ent_lba_start < table_lba + table_blocks ||
		    sent.ent_lba_end >= info->d_media_blocks ||
		    sent.ent_lba_start >= sent.ent_lba_end) {
			kprintf("%s part %d: unavailable, bad start or "
				"ending lba\n",
				sname, i);
		} else {
			gpt_setslice(sname, info, sp, &sent);
		}
	}
	ssp->dss_nslices = BASE_SLICE + i;

	error = 0;
done:
	if (bp1) {
		bp1->b_flags |= B_INVAL | B_AGE;
		brelse(bp1);
	}
	if (bp2) {
		bp2->b_flags |= B_INVAL | B_AGE;
		brelse(bp2);
	}
	if (error == EINVAL)
		error = 0;
	return (error);
}
Exemplo n.º 10
0
/*
 *	vnstrategy:
 *
 *	Run strategy routine for VN device.  We use VOP_READ/VOP_WRITE calls
 *	for vnode-backed vn's, and the swap_pager_strategy() call for
 *	vm_object-backed vn's.
 */
static int
vnstrategy(struct dev_strategy_args *ap)
{
	cdev_t dev = ap->a_head.a_dev;
	struct bio *bio = ap->a_bio;
	struct buf *bp;
	struct bio *nbio;
	int unit;
	struct vn_softc *vn;
	int error;

	unit = dkunit(dev);
	vn = dev->si_drv1;
	KKASSERT(vn != NULL);

	bp = bio->bio_buf;

	IFOPT(vn, VN_DEBUG)
		kprintf("vnstrategy(%p): unit %d\n", bp, unit);

	if ((vn->sc_flags & VNF_INITED) == 0) {
		bp->b_error = ENXIO;
		bp->b_flags |= B_ERROR;
		biodone(bio);
		return(0);
	}

	bp->b_resid = bp->b_bcount;

	/*
	 * The vnode device is using disk/slice label support.
	 *
	 * The dscheck() function is called for validating the
	 * slices that exist ON the vnode device itself, and
	 * translate the "slice-relative" block number, again.
	 * dscheck() will call biodone() and return NULL if
	 * we are at EOF or beyond the device size.
	 */

	nbio = bio;

	/*
	 * Use the translated nbio from this point on
	 */
	if (vn->sc_vp && bp->b_cmd == BUF_CMD_FREEBLKS) {
		/*
		 * Freeblks is not handled for vnode-backed elements yet.
		 */
		bp->b_resid = 0;
		/* operation complete */
	} else if (vn->sc_vp) {
		/*
		 * VNODE I/O
		 *
		 * If an error occurs, we set B_ERROR but we do not set 
		 * B_INVAL because (for a write anyway), the buffer is 
		 * still valid.
		 */
		struct uio auio;
		struct iovec aiov;

		bzero(&auio, sizeof(auio));

		aiov.iov_base = bp->b_data;
		aiov.iov_len = bp->b_bcount;
		auio.uio_iov = &aiov;
		auio.uio_iovcnt = 1;
		auio.uio_offset = nbio->bio_offset;
		auio.uio_segflg = UIO_SYSSPACE;
		if (bp->b_cmd == BUF_CMD_READ)
			auio.uio_rw = UIO_READ;
		else
			auio.uio_rw = UIO_WRITE;
		auio.uio_resid = bp->b_bcount;
		auio.uio_td = curthread;

		/*
		 * Don't use IO_DIRECT here, it really gets in the way
		 * due to typical blocksize differences between the
		 * fs backing the VN device and whatever is running on
		 * the VN device.
		 */
		switch (bp->b_cmd) {
		case (BUF_CMD_READ):
			vn_lock(vn->sc_vp, LK_SHARED | LK_RETRY);
			error = VOP_READ(vn->sc_vp, &auio, IO_RECURSE,
					 vn->sc_cred);
			break;

		case (BUF_CMD_WRITE):
			vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY);
			error = VOP_WRITE(vn->sc_vp, &auio, IO_RECURSE,
					  vn->sc_cred);
			break;

		case (BUF_CMD_FLUSH):
			auio.uio_resid = 0;
			vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY);
			error = VOP_FSYNC(vn->sc_vp, MNT_WAIT, 0);
			break;
		default:
			auio.uio_resid = 0;
			error = 0;
			break;
		}
		vn_unlock(vn->sc_vp);
		bp->b_resid = auio.uio_resid;
		if (error) {
			bp->b_error = error;
			bp->b_flags |= B_ERROR;
		}
		/* operation complete */
	} else if (vn->sc_object) {
		/*
		 * OBJT_SWAP I/O (handles read, write, freebuf)
		 *
		 * We have nothing to do if freeing  blocks on a reserved
		 * swap area, othrewise execute the op.
		 */
		if (bp->b_cmd == BUF_CMD_FREEBLKS && TESTOPT(vn, VN_RESERVE)) {
			bp->b_resid = 0;
			/* operation complete */
		} else {
			swap_pager_strategy(vn->sc_object, nbio);
			return(0);
			/* NOT REACHED */
		}
	} else {
		bp->b_resid = bp->b_bcount;
		bp->b_flags |= B_ERROR | B_INVAL;
		bp->b_error = EINVAL;
		/* operation complete */
	}
	biodone(nbio);
	return(0);
}
Exemplo n.º 11
0
Arquivo: hd.c Projeto: jamjr/Helios-NG
/*
 * 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.  All I/O requests must be a multiple
 * of a sector in length.
 */
int hd_strategy(struct buf *bp)
{
	u_int hdmajor = major(bp->b_dev);
	u_int unit = dkunit(bp->b_dev);
	u_int part = dkpart(bp->b_dev);
	struct disk *du = &(hd[hdmajor].disk[unit]);
	Semaphore *numbufs = &(hd[hdmajor].numbufs);
	struct buf *dp;
	struct partition *p;
	long maxsz, sz;
#ifdef MONITOR
printf("hd_strategy: Called with bp=0x%x, dev=%d, blck=%d  by %s\n",
	bp,bp->b_dev,bp->b_blkno,myprocname(returnlink_(bp)));
#endif
	/* Simple parameter check */
	if ((unit >= MAXDISKS) || (bp->b_blkno < 0) 
	    || (part >= du->dk_lab.d_npartitions)) {
		printf("hd_strategy: major=%d, unit=%d, part=%d, blkno=%d, bcount=%d\n",
			hdmajor,unit,part,bp->b_blkno,bp->b_bcount);
		printf("hd: Error in hd_strategy");
		bp->b_flags |= B_ERROR;
		goto bad;
	}

	/* Check for write protection */
	if (du->dk_protected && ((bp->b_flags & B_READ) == 0)) {
		printf("hd_strategy: %d:%d: write protected\n",hdmajor,unit);
		goto bad;
	}

	if (DISKSTATE(du->dk_state) != OPEN)
		goto q;

	/* Determine size of xfer and make sure it fits. */
	p = &(du->dk_lab.d_partitions[part]);
	maxsz = p->p_size;
	sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;

	/* XXX Check disk label writing at a later stage */

	/* Check the parameters */
	if ((bp->b_blkno < 0) || ((bp->b_blkno + sz) > maxsz)) {
		/* if exactly at end of disk, return an EOF. */
		if (bp->b_blkno == maxsz) {
			bp->b_resid = bp->b_bcount;
			biodone(bp);
			return(0);
		}
		/* or truncate if part of it fits */
		sz = maxsz - bp->b_blkno;
		if (sz <= 0) {
			printf("hd%d: invalid size %d\n",unit,sz);
			goto bad;
		}
		bp->b_bcount = sz << DEV_BSHIFT;
	}
	bp->b_cylin = (bp->b_blkno + p->p_offset) / du->dk_lab.d_secpercyl;

q:
	dp = &(du->dk_queue);

	/* Lock buffer head, add item, free buffer head and signal */
	Wait(&du->dk_guard);		/* Lock */
	disksort(dp, bp);		/* Add */
	Signal(&du->dk_guard);		/* Free */
	Signal(&du->dk_numq);		/* Signal another buffer in this q */
	Signal(numbufs);		/* Signal Device Driver */
	
#ifdef MONITOR
printf("hd_strategy: Done OK\n");
#endif
	return(0);

bad:
#ifdef MONITOR
printf("hd_strategy: Done Failed\n");
#endif
printf("hd_strategy: bad error\n");
	bp->b_error = EINVAL;
	biodone(bp);
	return(1);
}
Exemplo n.º 12
0
Arquivo: hd.c Projeto: jamjr/Helios-NG
/*
 * The ioctl routine.  
 */
int hd_ioctl(dev_t dev, int cmd, caddr_t addr, int flag)
{
	u_int major = major(dev);
	u_int unit = dkunit(dev);
	u_int part = dkpart(dev);
	struct disk *du;
	int error = 0;

#ifdef MONITOR
printf("hd_ioctl: Called with dev=%d,  cmd=0x%x,  flag=%d  by %s\n",
	dev,cmd,flag,myprocname(returnlink_(dev)));
printf("DIOCGDINFO:%x DIOCGPART:%x DIOCSDINFO:%x \n\tDIOCWLABEL:%x DIOCWDINFO:%x\n",
	DIOCGDINFO,DIOCGPART,DIOCSDINFO,DIOCWLABEL,DIOCWDINFO);
#endif

	if ((unit >= MAXDISKS) || (part >= MAXPARTITIONS)) return(ENXIO);
	du = &hd[major].disk[unit];

	switch(cmd) {
	case DIOCGDINFO:
		*(struct disklabel *)addr = du->dk_lab;
#ifdef DEBUG
printf("hd_ioctl: dev_bsize = %d\n",du->dk_lab.d_secsize);
#endif
		break;
	case DIOCGPART:
		((struct partinfo *)addr)->disklab = &du->dk_lab;
		((struct partinfo *)addr)->part =
			&du->dk_lab.d_partitions[part];
		break;
	case DIOCSDINFO:
		if ((flag & FWRITE) == 0)
			error = EBADF;
		else
			error = setdisklabel(&du->dk_lab,
					(struct disklabel *)addr,0);
		/* XXX AMS Set this info at controller as well. */
		break;
	case DIOCWLABEL:
		if ((flag & FWRITE) == 0)
			error = EBADF;
		else
			du->dk_wlabel = *(int *)addr;
		break;
	case DIOCWDINFO:
		if ((flag & FWRITE) == 0) {
			error = EBADF;
		} else if ((error = setdisklabel(&du->dk_lab,
					(struct disklabel *)addr,0)) == 0) {
			int wlab;

			/* XXX AMS Set this info at controller as well. */
			wlab = du->dk_wlabel;
			du->dk_wlabel = 1;
			error = writedisklabel(dev,hd_strategy,
						&du->dk_lab,part);
			du->dk_wlabel = wlab;			
		}
		break;
	default:
		error = ENOTTY;
		break;
	}

	return(error);
}
Exemplo n.º 13
0
Arquivo: hd.c Projeto: jamjr/Helios-NG
/*
 * Close a drive.
 */
int hd_close(dev_t dev, int flags, int fmt)
{
	u_int major, unit, part;
	struct disk *du;
	struct hd_devices *hdev;
	DCB *dcb;
	
#ifdef MONITOR
printf("hd_close: Called with dev=%d,  flags=%d,   fmt=%d  by %s\n",
	dev,flags,fmt,myprocname(returnlink_(dev)));
#endif
	
	/* Get the unit info */
	major = major(dev);
	unit = dkunit(dev);
	part = dkpart(dev);
	hdev = &hd[major];
	dcb = hdev->dcb;
	if (unit >= MAXDISKS) return(ENXIO);
	du = &(hdev->disk[unit]);

	if (du->dk_state == CLOSED) return(0);
	if (du->dk_state == RAWOPEN) {
		du->dk_state = CLOSED;
		for (part=0; part<MAXPARTITIONS; part++)
			du->dk_pstatus[part] = CLOSED;
		goto done;
	}

	part = dkpart(dev);
	if (part >= du->dk_lab.d_npartitions) return(ENXIO);
	du->dk_pstatus[part] = CLOSED;
	for (part=0; 
		(part<MAXPARTITIONS) && (du->dk_pstatus[part] == CLOSED); 
		part++);
	if (part == MAXPARTITIONS) du->dk_state = CLOSED;

done:
	if (du->dk_state == CLOSED) {
	   if (hdev->old) {
		hdev->old = FALSE;	/* Only unit open now closed */
#ifdef DEBUG
printf("old unit dev %d was closed",dev);
#endif
	   } else {
		DiscOpenCloseReq openreq;

		openreq.DevReq.Request = FG_Close;
		openreq.DevReq.Action = dev_openaction;
		openreq.DevReq.SubDevice = unit;
		openreq.DevReq.Timeout = -1;
		openreq.DevReq.Result = MYSPECCODE;	/* Special Code */
		InitSemaphore(&(openreq.WaitLock),0);
		Operate(dcb,&openreq);
		Wait(&(openreq.WaitLock));

		if (openreq.DevReq.Result)
		  printf("hd_close: Warning, Fault 0x%x on major dev %d\n",
			 (openreq.DevReq.Result==MYSPECCODE) ?
			   (SS_Device|EC_Error|EG_WrongFn|EO_Medium):
			   openreq.DevReq.Result,
			 major);
	    }
	}

	return(0);
}
Exemplo n.º 14
0
Arquivo: hd.c Projeto: jamjr/Helios-NG
int hd_open(dev_t dev, int flags, int fmt)
{
	u_int major, unit, part;
	struct disk *du;
	struct hd_devices *hdev;
	DCB *dcb;
	DiscOpenCloseReq openreq;
	DiscParameterReq dpreq;
	struct buf *bp;
	int error = 0;
	int wasold = FALSE;

#ifdef MONITOR
 printf("hd_open: Called with dev=%d,  flags=%d,   fmt=%d  by %s\n",
	dev,flags,fmt,myprocname(returnlink_(dev)));
#endif
	/* Get the unit info */
	major = major(dev);
	unit = dkunit(dev);
	part = dkpart(dev);
	hdev = &hd[major];
	dcb = hd[major].dcb;
	if (unit >= MAXDISKS) return(ENXIO);
	du = &(hdev->disk[unit]);

#ifdef DEBUG
printf("hd_open: major %d  unit %d  part %d\n",major,unit,part);
#endif

	/* Has the disk already been opened. */
	if (du->dk_state != CLOSED) {
		/* Already open, so don't mess with it. */
		goto getpart;
	}

	/* Undefined device OR Trap old device driver compatibility */
	if ((dcb == NULL) || hdev->old) {
		/* Old style only supports 1 disk */
		return(ENODEV);
	}

	/* Open the actual disk */
	openreq.DevReq.Request = FG_Open;
	openreq.DevReq.Action = dev_openaction;
	openreq.DevReq.SubDevice = unit;
	openreq.DevReq.Timeout = -1;
	openreq.DevReq.Result = MYSPECCODE;	/* Special Code */
	InitSemaphore(&(openreq.WaitLock),0);
	Operate(dcb,&openreq);
	Wait(&(openreq.WaitLock));

	/* Old style device driver was opened */
	if ((openreq.DevReq.Result == MYSPECCODE) || 
	    ((openreq.DevReq.Result & EG_Mask) == EG_WrongFn))  {
		wasold = TRUE;
	} else if (openreq.DevReq.Result) {
		/* Error in opening device */
		return(ENODEV);
	}

	/* Get the disk label using device driver defaults */
	du->dk_lab = dflt_sizes;
	du->dk_state = READLABEL;
	bp = geteblk(DEV_BSIZE);
	bp->b_dev = dev & 0xFFFFFFF8;	/* Force to boot partition (a) */
	bp->b_blkno = LABELSECTOR;
	bp->b_flags = B_READ;
	hd_strategy(bp);		/* Start the operation. */
	biowait(bp);			/* Wait until complete */
	if (bp->b_flags & B_ERROR) {
		error = ENXIO;
		du->dk_state = CLOSED;
		goto done;
	}

	/* Is label there, otherwise open as raw. */
	if (((struct disklabel *)
	    (bp->b_un.b_addr + LABELOFFSET))->d_magic == DISKMAGIC) {
		du->dk_lab = *(struct disklabel *)
				(bp->b_un.b_addr + LABELOFFSET);
		du->dk_state = OPEN;

		/* Pass disk information back to device driver */
		/* Standard Request */
		dpreq.DevReq.Request = FG_SetInfo;
		dpreq.DevReq.Result = MYSPECCODE;
		dpreq.DevReq.Action = dev_openaction;
		dpreq.DevReq.SubDevice = unit;
		dpreq.DevReq.Timeout = -1;
		InitSemaphore(&dpreq.WaitLock,0);

		/* Setup SetInfo parameters */
		dpreq.DriveType = 0;	/* Fixed Disk ? */
		dpreq.SectorSize = du->dk_lab.d_secsize;
		dpreq.SectorsPerTrack = du->dk_lab.d_nsectors;
		dpreq.TracksPerCyl = du->dk_lab.d_ntracks;
		dpreq.Cylinders = du->dk_lab.d_ncylinders;

		/* Make it */
		Operate(dcb,&dpreq);
		Wait(&(dpreq.WaitLock));
			
		if (dpreq.DevReq.Result)
		  printf("hd_open: Warning; Fault 0x%x on major dev %d FG_SetInfo\n",
			 (dpreq.DevReq.Result==MYSPECCODE) ?
			   (SS_Device|EC_Error|EG_WrongFn|EO_Medium):
			   dpreq.DevReq.Result,
			 major);
	} else {
		printf("hd (dev %d): Bad disk label (%x)\n",bp->b_dev,
    ((struct disklabel *)(bp->b_un.b_addr + LABELOFFSET))->d_magic);
		du->dk_state = RAWOPEN;
	}

done:
	/* Release buffer. */
	bp->b_flags = B_INVAL | B_AGE;
	brelse(bp);

getpart:
#ifdef DEBUG
printf("hd_open: device %d get part %d\n",dev,part);
#endif
	/* Get and set the partition info */
	if (part >= MAXPARTITIONS) return(ENXIO);
	if (du->dk_pstatus[part] != CLOSED) {
		/* Partition is already open, don't mess with it. */
#ifdef DEBUG
printf("hd_open: device %d part %d already open\n",dev,part);
#endif
		return(0);
	}
	if (du->dk_state == RAWOPEN) {
#ifdef DEBUG
printf("hd_open: device %d open as raw part %d\n",dev,part);
#endif
		/* If no label, then only allow raw */
		if (part == (RAWPARTITION - 'a')) {
#ifdef DEBUG
printf("hd_open: device %d opened as raw\n",dev);
#endif
			du->dk_pstatus[part] = RAWOPEN;
		} else {
			du->dk_state = CLOSED;
#ifdef DEBUG
printf("hd_open: device %d refused opening partition %d as raw\n",dev,part);
#endif
			return(ENXIO);	
		}
	} else {
		/* Label found, so check overlap with other open partitions */
		struct partition *pp;
		int start,end,i;

		if (part >= du->dk_lab.d_npartitions) return(ENXIO);
		
		pp = &du->dk_lab.d_partitions[part];
		start = pp->p_offset;
		end = start + pp->p_size;
		for (pp = du->dk_lab.d_partitions, i=0;
		     i < du->dk_lab.d_npartitions;
		     pp++, i++) {
			/* Ends before this starts or starts before this ends */
			if (pp->p_offset + pp->p_size <= start ||
			    pp->p_offset >= end)
				continue;
			if (du->dk_pstatus[i]) {
				printf("hd%d%c: overlaps open partition (%c)\n",
				    unit,part+'a',i+'a');
			}
		}

		du->dk_pstatus[part] = OPEN;
	}
#ifdef DEBUG
printf("hd_open: device %d opened error=%d\n",dev,error);
#endif
	if (!error && wasold) hdev->old = TRUE;
	return(error);
}
Exemplo n.º 15
0
int
mbrinit(cdev_t dev, struct disk_info *info, struct diskslices **sspp)
{
	struct buf *bp;
	u_char	*cp;
	int	dospart;
	struct dos_partition *dp;
	struct dos_partition *dp0;
	struct dos_partition dpcopy[NDOSPART];
	int	error;
	int	max_ncyls;
	int	max_nsectors;
	int	max_ntracks;
	u_int64_t mbr_offset;
	char	partname[2];
	u_long	secpercyl;
	char	*sname = "tempname";
	struct diskslice *sp;
	struct diskslices *ssp;
	cdev_t wdev;

	mbr_offset = DOSBBSECTOR;
reread_mbr:
	/*
	 * Don't bother if the block size is weird or the
	 * media size is 0 (probably means no media present).
	 */
	if (info->d_media_blksize & DEV_BMASK)
		return (EIO);
	if (info->d_media_size == 0)
		return (EIO);

	/*
	 * Read master boot record.
	 */
	wdev = dev;
	bp = geteblk((int)info->d_media_blksize);
	bp->b_bio1.bio_offset = (off_t)mbr_offset * info->d_media_blksize;
	bp->b_bio1.bio_done = biodone_sync;
	bp->b_bio1.bio_flags |= BIO_SYNC;
	bp->b_bcount = info->d_media_blksize;
	bp->b_cmd = BUF_CMD_READ;
	bp->b_flags |= B_FAILONDIS;
	dev_dstrategy(wdev, &bp->b_bio1);
	if (biowait(&bp->b_bio1, "mbrrd") != 0) {
		if ((info->d_dsflags & DSO_MBRQUIET) == 0) {
			diskerr(&bp->b_bio1, wdev,
				"reading primary partition table: error",
				LOG_PRINTF, 0);
			kprintf("\n");
		}
		error = EIO;
		goto done;
	}

	/* Weakly verify it. */
	cp = bp->b_data;
	sname = dsname(dev, 0, 0, 0, NULL);
	if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) {
		if (bootverbose)
			kprintf("%s: invalid primary partition table: no magic\n",
			       sname);
		error = EINVAL;
		goto done;
	}

	/* Make a copy of the partition table to avoid alignment problems. */
	memcpy(&dpcopy[0], cp + DOSPARTOFF, sizeof(dpcopy));

	dp0 = &dpcopy[0];

	/*
	 * Check for "Ontrack Diskmanager" or GPT.  If a GPT is found in
	 * the first dos partition, ignore the rest of the MBR and go
	 * to GPT processing.
	 */
	for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) {
		if (dospart == 0 &&
		    (dp->dp_typ == DOSPTYP_PMBR || dp->dp_typ == DOSPTYP_GPT)) {
			if (bootverbose)
				kprintf(
	    "%s: Found GPT in slice #%d\n", sname, dospart + 1);
			error = gptinit(dev, info, sspp);
			goto done;
		}

		if (dp->dp_typ == DOSPTYP_ONTRACK) {
			if (bootverbose)
				kprintf(
	    "%s: Found \"Ontrack Disk Manager\" on this disk.\n", sname);
			bp->b_flags |= B_INVAL | B_AGE;
			brelse(bp);
			mbr_offset = 63;
			goto reread_mbr;
		}
	}

	if (bcmp(dp0, historical_bogus_partition_table,
		 sizeof historical_bogus_partition_table) == 0 ||
	    bcmp(dp0, historical_bogus_partition_table_fixed,
		 sizeof historical_bogus_partition_table_fixed) == 0) {
#if 0
		TRACE(("%s: invalid primary partition table: historical\n",
		       sname));
#endif /* 0 */
		if (bootverbose)
			kprintf(
     "%s: invalid primary partition table: Dangerously Dedicated (ignored)\n",
			       sname);
		error = EINVAL;
		goto done;
	}

	/* Guess the geometry. */
	/*
	 * TODO:
	 * Perhaps skip entries with 0 size.
	 * Perhaps only look at entries of type DOSPTYP_386BSD.
	 */
	max_ncyls = 0;
	max_nsectors = 0;
	max_ntracks = 0;
	for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) {
		int	ncyls;
		int	nsectors;
		int	ntracks;

		ncyls = DPCYL(dp->dp_ecyl, dp->dp_esect) + 1;
		if (max_ncyls < ncyls)
			max_ncyls = ncyls;
		nsectors = DPSECT(dp->dp_esect);
		if (max_nsectors < nsectors)
			max_nsectors = nsectors;
		ntracks = dp->dp_ehd + 1;
		if (max_ntracks < ntracks)
			max_ntracks = ntracks;
	}

	/*
	 * Check that we have guessed the geometry right by checking the
	 * partition entries.
	 */
	/*
	 * TODO:
	 * As above.
	 * Check for overlaps.
	 * Check against d_secperunit if the latter is reliable.
	 */
	error = 0;
	for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) {
		if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0
		    && dp->dp_start == 0 && dp->dp_size == 0)
			continue;
		//sname = dsname(dev, dkunit(dev), BASE_SLICE + dospart,
		//	       WHOLE_SLICE_PART, partname);

		/*
		 * Temporarily ignore errors from this check.  We could
		 * simplify things by accepting the table eariler if we
		 * always ignore errors here.  Perhaps we should always
		 * accept the table if the magic is right but not let
		 * bad entries affect the geometry.
		 */
		check_part(sname, dp, mbr_offset, max_nsectors, max_ntracks,
			   mbr_offset);
	}
	if (error != 0)
		goto done;

	/*
	 * Accept the DOS partition table.
	 *
	 * Adjust the disk information structure with updated CHS
	 * conversion parameters, but only use values extracted from
	 * the primary partition table.
	 *
	 * NOTE!  Regardless of our having to deal with this old cruft,
	 * we do not screw around with the info->d_media* parameters.
	 */
	secpercyl = (u_long)max_nsectors * max_ntracks;
	if (secpercyl != 0 && mbr_offset == DOSBBSECTOR) {
		info->d_secpertrack = max_nsectors;
		info->d_nheads = max_ntracks;
		info->d_secpercyl = secpercyl;
		info->d_ncylinders = info->d_media_blocks / secpercyl;
	}

	/*
	 * We are passed a pointer to a suitably initialized minimal
	 * slices "struct" with no dangling pointers in it.  Replace it
	 * by a maximal one.  This usually oversizes the "struct", but
	 * enlarging it while searching for logical drives would be
	 * inconvenient.
	 */
	kfree(*sspp, M_DEVBUF);
	ssp = dsmakeslicestruct(MAX_SLICES, info);
	*sspp = ssp;

	/* Initialize normal slices. */
	sp = &ssp->dss_slices[BASE_SLICE];
	for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++, sp++) {
		sname = dsname(dev, dkunit(dev), BASE_SLICE + dospart,
			       WHOLE_SLICE_PART, partname);
		(void)mbr_setslice(sname, info, sp, dp, mbr_offset);
	}
	ssp->dss_nslices = BASE_SLICE + NDOSPART;

	/* Handle extended partitions. */
	sp -= NDOSPART;
	for (dospart = 0; dospart < NDOSPART; dospart++, sp++) {
		if (sp->ds_type == DOSPTYP_EXTENDED ||
		    sp->ds_type == DOSPTYP_EXTENDEDX) {
			mbr_extended(wdev, info, ssp,
				     sp->ds_offset, sp->ds_size, sp->ds_offset,
				     max_nsectors, max_ntracks, mbr_offset, 1);
		}
	}

	/*
	 * mbr_extended() abuses ssp->dss_nslices for the number of slices
	 * that would be found if there were no limit on the number of slices
	 * in *ssp.  Cut it back now.
	 */
	if (ssp->dss_nslices > MAX_SLICES)
		ssp->dss_nslices = MAX_SLICES;

done:
	bp->b_flags |= B_INVAL | B_AGE;
	brelse(bp);
	if (error == EINVAL)
		error = 0;
	return (error);
}
Exemplo n.º 16
0
/* 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*/;
}
Exemplo n.º 17
0
static int
disk_probe_slice(struct disk *dp, cdev_t dev, int slice, int reprobe)
{
	struct disk_info *info = &dp->d_info;
	struct diskslice *sp = &dp->d_slice->dss_slices[slice];
	disklabel_ops_t ops;
	struct partinfo part;
	const char *msg;
	char uuid_buf[128];
	cdev_t ndev;
	int sno;
	u_int i;

	disk_debug(2, "disk_probe_slice (begin): %s (%s)\n",
		   dev->si_name, dp->d_cdev->si_name);

	sno = slice ? slice - 1 : 0;

	ops = &disklabel32_ops;
	msg = ops->op_readdisklabel(dev, sp, &sp->ds_label, info);
	if (msg && !strcmp(msg, "no disk label")) {
		ops = &disklabel64_ops;
		msg = ops->op_readdisklabel(dev, sp, &sp->ds_label, info);
	}

	if (msg == NULL) {
		if (slice != WHOLE_DISK_SLICE)
			ops->op_adjust_label_reserved(dp->d_slice, slice, sp);
		else
			sp->ds_reserved = 0;

		sp->ds_ops = ops;
		for (i = 0; i < ops->op_getnumparts(sp->ds_label); i++) {
			ops->op_loadpartinfo(sp->ds_label, i, &part);
			if (part.fstype) {
				if (reprobe &&
				    (ndev = devfs_find_device_by_name("%s%c",
						dev->si_name, 'a' + i))
				) {
					/*
					 * Device already exists and
					 * is still valid.
					 */
					ndev->si_flags |= SI_REPROBE_TEST;

					/*
					 * Destroy old UUID alias
					 */
					destroy_dev_alias(ndev, "part-by-uuid/*");

					/* Create UUID alias */
					if (!kuuid_is_nil(&part.storage_uuid)) {
						snprintf_uuid(uuid_buf,
						    sizeof(uuid_buf),
						    &part.storage_uuid);
						make_dev_alias(ndev,
						    "part-by-uuid/%s",
						    uuid_buf);
						udev_dict_set_cstr(ndev, "uuid", uuid_buf);
					}
				} else {
					ndev = make_dev_covering(&disk_ops, dp->d_rawdev->si_ops,
						dkmakeminor(dkunit(dp->d_cdev),
							    slice, i),
						UID_ROOT, GID_OPERATOR, 0640,
						"%s%c", dev->si_name, 'a'+ i);
					ndev->si_parent = dev;
					ndev->si_iosize_max = dev->si_iosize_max;
					ndev->si_disk = dp;
					udev_dict_set_cstr(ndev, "subsystem", "disk");
					/* Inherit parent's disk type */
					if (dp->d_disktype) {
						udev_dict_set_cstr(ndev, "disk-type",
						    __DECONST(char *, dp->d_disktype));
					}

					/* Create serno alias */
					if (dp->d_info.d_serialno) {
						make_dev_alias(ndev,
						    "serno/%s.s%d%c",
						    dp->d_info.d_serialno,
						    sno, 'a' + i);
					}

					/* Create UUID alias */
					if (!kuuid_is_nil(&part.storage_uuid)) {
						snprintf_uuid(uuid_buf,
						    sizeof(uuid_buf),
						    &part.storage_uuid);
						make_dev_alias(ndev,
						    "part-by-uuid/%s",
						    uuid_buf);
						udev_dict_set_cstr(ndev, "uuid", uuid_buf);
					}
					ndev->si_flags |= SI_REPROBE_TEST;
				}
			}
		}
	} else if (info->d_dsflags & DSO_COMPATLABEL) {
Exemplo n.º 18
0
Arquivo: hd.c Projeto: jamjr/Helios-NG
static void hd_intr_server(int major)
{
	struct hd_devices *hdev = &hd[major];
	Semaphore *numbufs = &(hdev->numbufs);
	Semaphore *abort = &(hdev->abort);
	DCB *dcb = hdev->dcb;
	struct disk *this_hd = &(hdev->disk[0]);	/* Start at 0 */
	struct disk *last_hd = &(hdev->disk[MAXDISKS]);	/* Terminate check */
	int searched;
	DiscReq req;
	struct partition *pp;
	struct buf *dp, *bp;
#ifdef DEBUG
printf("hd_intr_server: Helios Major device %d running\n",major);
#endif
	/* Loop until ordered to shut down and no more buffers to work on. */
	for (;;) {
		/* Wait for a block to work on. */
		Wait(numbufs);
		if (TestWait(abort)) {
			/* Forget anything else */
			return;
		}

		/* Look for a disk to work on */
		searched = 0;
		while (!TestWait(&this_hd->dk_numq) && searched != MAXDISKS) {
			this_hd++;
			searched++;
			if (this_hd >= last_hd)
				this_hd = &(hdev->disk[0]);
		}
		if (searched == MAXDISKS) {
			printf("hd_intr: PANIC %d, Failed to find buffer\n",major);
			continue;
		}

		/* Extract the buffer */
		dp = &(this_hd->dk_queue);
		bp = dp->b_actf;

		/* Get the partition (offset) */
		pp = &(this_hd->dk_lab.d_partitions[dkpart(bp->b_dev)]);

		/* Perform the operation */
		req.DevReq.Request = ((bp->b_flags & B_READ)?FG_Read:FG_Write);
		req.DevReq.Action = hd_iodone;
		req.DevReq.SubDevice = dkunit(bp->b_dev);
		req.DevReq.Timeout = -1;	/* No Timeout */
		req.Size = bp->b_bcount;
		req.Buf =  bp->b_un.b_addr;
		req.Pos = bp->b_blkno + pp->p_offset;	/* Sector */

		/* Check if we are writing a disk label */
		if ((req.Pos <= LABELSECTOR) && (!this_hd->dk_wlabel) &&
		    (req.DevReq.Request == FG_Write)) {
			bp->b_error = EACCES;	/* Not writeable */
			goto skip;
		}

		/* Adjust to byte location */
		req.Pos *= this_hd->dk_lab.d_secsize;
#ifdef DEBUG
printf("hd_intr_server: Major %d performing %s on dev=%d  buf=0x%x (dcb=0x%x)\n",
	major,((bp->b_flags & B_READ)?"Read":"Write"),bp->b_dev,buf,dcb);
printf("hd_intr_server: Request=0x%x, SubDevice=%d, Timeout=%d, Size=%d\n",
	req.DevReq.Request,req.DevReq.SubDevice,req.DevReq.Timeout,req.Size);
#endif
		InitSemaphore(&(req.WaitLock),0);
		Operate(dcb,&req);
		Wait(&(req.WaitLock));		/* XXX Implement multiple ops
						 * later.  (i.e.TestWait for
						 * each disk)
						 */
hd_ops++;
#ifdef DEBUG
printf("hd_intr_server:  Major%d Pos=%d, Buf=0x%x  Actual=%d  %s\n",
	major,req.Pos,req.Buf,req.Actual,
	(req.Size==req.Actual)?"O.K.":"ERROR");
#endif

		/* Any problems ? */
		if (req.Size == req.Actual) {
			bp->b_error = 0;
		} else {
			/* Error occurred */
			bp->b_error = EIO;
			bp->b_flags |= B_ERROR;
		}

		/* Operation complete, lock queue and remove bp */
skip:
		Wait(&this_hd->dk_guard);
		dp->b_actf = bp->av_forw;
		bp->b_resid = 0;
		bp->av_forw = NULL;
		Signal(&this_hd->dk_guard);

		/* Need to go into UNIX kernel to call biodone */
		tokernel();
		biodone(bp);
		fromkernel();

		/* Round robin scheduling */
		this_hd++;
		if (this_hd >= last_hd) this_hd = &(hdev->disk[0]);

	}
}