/* 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)); }
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); }
/* 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; }
/* * 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)); }
/* * 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; }
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); }
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); }
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); }
/* * 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); }
/* * 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); }
/* * 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); }
/* * 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); }
/* * 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); }
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); }
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); }
/* 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*/; }
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) {
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]); } }