subr_disk.c revision 77147
150565Sphk/* 250565Sphk * ---------------------------------------------------------------------------- 350565Sphk * "THE BEER-WARE LICENSE" (Revision 42): 450565Sphk * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 550565Sphk * can do whatever you want with this stuff. If we meet some day, and you think 650565Sphk * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 750565Sphk * ---------------------------------------------------------------------------- 850565Sphk * 950565Sphk * $FreeBSD: head/sys/kern/subr_disk.c 77147 2001-05-24 20:27:16Z phk $ 1050565Sphk * 1150565Sphk */ 1250565Sphk 1350565Sphk#include <sys/param.h> 1450565Sphk#include <sys/systm.h> 1550565Sphk#include <sys/kernel.h> 1651111Sjulian#include <sys/sysctl.h> 1760041Sphk#include <sys/bio.h> 1850565Sphk#include <sys/conf.h> 1950565Sphk#include <sys/disk.h> 2050565Sphk#include <sys/malloc.h> 2161953Snbm#include <sys/sysctl.h> 2250728Sphk#include <machine/md_var.h> 2364880Sphk#include <sys/ctype.h> 2464880Sphk 2569774Sphkstatic MALLOC_DEFINE(M_DISK, "disk", "disk data"); 2650565Sphk 2750565Sphkstatic d_strategy_t diskstrategy; 2850565Sphkstatic d_open_t diskopen; 2950565Sphkstatic d_close_t diskclose; 3050565Sphkstatic d_ioctl_t diskioctl; 3150565Sphkstatic d_psize_t diskpsize; 3261717Sphk 3361717Sphkstatic LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist); 3464880Sphk 3562617Simpstatic void 3664880Sphkdisk_clone(void *arg, char *name, int namelen, dev_t *dev) 3764880Sphk{ 3864880Sphk struct disk *dp; 3964880Sphk char const *d; 4064880Sphk int i, u, s, p; 4164880Sphk dev_t pdev; 4264880Sphk 4364880Sphk if (*dev != NODEV) 4464880Sphk return; 4564880Sphk 4664880Sphk LIST_FOREACH(dp, &disklist, d_list) { 4764880Sphk d = dp->d_devsw->d_name; 4864880Sphk i = strlen(d); 4964880Sphk if (bcmp(d, name, i) != 0) 5064880Sphk continue; 5164880Sphk u = 0; 5264880Sphk if (!isdigit(name[i])) 5364880Sphk continue; 5464880Sphk while (isdigit(name[i])) { 5564880Sphk u *= 10; 5664880Sphk u += name[i++] - '0'; 5764880Sphk } 5870058Sphk if (u > DKMAXUNIT) 5970058Sphk continue; 6064880Sphk p = RAW_PART; 6164880Sphk s = WHOLE_DISK_SLICE; 6264880Sphk pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p)); 6364880Sphk if (pdev->si_disk == NULL) 6464880Sphk continue; 6564880Sphk if (name[i] != '\0') { 6664880Sphk if (name[i] == 's') { 6764880Sphk s = 0; 6864880Sphk i++; 6964880Sphk if (!isdigit(name[i])) 7064880Sphk continue; 7164880Sphk while (isdigit(name[i])) { 7264880Sphk s *= 10; 7364880Sphk s += name[i++] - '0'; 7464880Sphk } 7564880Sphk s += BASE_SLICE - 1; 7664880Sphk } else { 7764880Sphk s = COMPATIBILITY_SLICE; 7864880Sphk } 7964880Sphk if (name[i] == '\0') 8064880Sphk ; 8164880Sphk else if (name[i] < 'a' || name[i] > 'h') 8264880Sphk continue; 8364880Sphk else 8464880Sphk p = name[i] - 'a'; 8564880Sphk } 8664880Sphk 8764880Sphk *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 8864880Sphk UID_ROOT, GID_OPERATOR, 0640, name); 8964880Sphk return; 9064880Sphk } 9164880Sphk} 9264880Sphk 9364880Sphkstatic void 9462617Simpinherit_raw(dev_t pdev, dev_t dev) 9562617Simp{ 9662617Simp dev->si_disk = pdev->si_disk; 9762617Simp dev->si_drv1 = pdev->si_drv1; 9862617Simp dev->si_drv2 = pdev->si_drv2; 9962617Simp dev->si_iosize_max = pdev->si_iosize_max; 10062617Simp dev->si_bsize_phys = pdev->si_bsize_phys; 10162617Simp dev->si_bsize_best = pdev->si_bsize_best; 10262617Simp} 10362617Simp 10450565Sphkdev_t 10551215Sphkdisk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto) 10650565Sphk{ 10764880Sphk static int once; 10850565Sphk dev_t dev; 10950565Sphk 11051198Sphk bzero(dp, sizeof(*dp)); 11151198Sphk 11277147Sphk if (proto->d_open != diskopen) { 11351215Sphk *proto = *cdevsw; 11451215Sphk proto->d_open = diskopen; 11551215Sphk proto->d_close = diskclose; 11651215Sphk proto->d_ioctl = diskioctl; 11751215Sphk proto->d_strategy = diskstrategy; 11851215Sphk proto->d_psize = diskpsize; 11950565Sphk } 12050565Sphk 12153437Sjkh if (bootverbose) 12253437Sjkh printf("Creating DISK %s%d\n", cdevsw->d_name, unit); 12351243Sphk dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART), 12464880Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit); 12550565Sphk 12650565Sphk dev->si_disk = dp; 12750565Sphk dp->d_dev = dev; 12852917Sphk dp->d_dsflags = flags; 12951215Sphk dp->d_devsw = cdevsw; 13061717Sphk LIST_INSERT_HEAD(&disklist, dp, d_list); 13164880Sphk if (!once) { 13265374Sphk EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000); 13364880Sphk once++; 13464880Sphk } 13550565Sphk return (dev); 13650565Sphk} 13750565Sphk 13850728Sphkint 13950728Sphkdisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize) 14050728Sphk{ 14150728Sphk struct disk *dp; 14250728Sphk struct disklabel *dl; 14350728Sphk u_int boff; 14450728Sphk 14550728Sphk dp = dev->si_disk; 14650728Sphk if (!dp) 14750728Sphk return (ENXIO); 14850728Sphk if (!dp->d_slice) 14950728Sphk return (ENXIO); 15050728Sphk dl = dsgetlabel(dev, dp->d_slice); 15150728Sphk if (!dl) 15250728Sphk return (ENXIO); 15350728Sphk *count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize; 15450728Sphk if (dumplo < 0 || 15550728Sphk (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size)) 15650728Sphk return (EINVAL); 15750728Sphk boff = dl->d_partitions[dkpart(dev)].p_offset + 15850728Sphk dp->d_slice->dss_slices[dkslice(dev)].ds_offset; 15950728Sphk *blkno = boff + dumplo; 16050728Sphk *secsize = dl->d_secsize; 16150728Sphk return (0); 16250728Sphk 16350728Sphk} 16450728Sphk 16550728Sphkvoid 16650728Sphkdisk_invalidate (struct disk *disk) 16750728Sphk{ 16857325Ssos if (disk->d_slice) 16957325Ssos dsgone(&disk->d_slice); 17050728Sphk} 17150728Sphk 17250565Sphkvoid 17356767Sphkdisk_destroy(dev_t dev) 17450565Sphk{ 17561717Sphk LIST_REMOVE(dev->si_disk, d_list); 17661717Sphk bzero(dev->si_disk, sizeof(*dev->si_disk)); 17757325Ssos dev->si_disk = NULL; 17857325Ssos destroy_dev(dev); 17950565Sphk return; 18050565Sphk} 18150565Sphk 18261717Sphkstruct disk * 18361717Sphkdisk_enumerate(struct disk *disk) 18461717Sphk{ 18561717Sphk if (!disk) 18661717Sphk return (LIST_FIRST(&disklist)); 18761717Sphk else 18861717Sphk return (LIST_NEXT(disk, d_list)); 18961717Sphk} 19061717Sphk 19161953Snbmstatic int 19262573Sphksysctl_disks(SYSCTL_HANDLER_ARGS) 19361953Snbm{ 19461953Snbm struct disk *disk; 19561953Snbm int error, first; 19661953Snbm 19761953Snbm disk = NULL; 19861953Snbm first = 1; 19961953Snbm 20061953Snbm while ((disk = disk_enumerate(disk))) { 20161953Snbm if (!first) { 20261953Snbm error = SYSCTL_OUT(req, " ", 1); 20361953Snbm if (error) 20461953Snbm return error; 20561953Snbm } else { 20661953Snbm first = 0; 20761953Snbm } 20861953Snbm error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name)); 20961953Snbm if (error) 21061953Snbm return error; 21161953Snbm } 21261953Snbm error = SYSCTL_OUT(req, "", 1); 21361953Snbm return error; 21461953Snbm} 21561953Snbm 21661953SnbmSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL, 21761953Snbm sysctl_disks, "A", "names of available disks"); 21861953Snbm 21950728Sphk/* 22050728Sphk * The cdevsw functions 22150728Sphk */ 22250728Sphk 22350565Sphkstatic int 22450565Sphkdiskopen(dev_t dev, int oflags, int devtype, struct proc *p) 22550565Sphk{ 22650565Sphk dev_t pdev; 22750565Sphk struct disk *dp; 22850565Sphk int error; 22950565Sphk 23050728Sphk error = 0; 23150565Sphk pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 23250728Sphk 23350565Sphk dp = pdev->si_disk; 23450565Sphk if (!dp) 23550565Sphk return (ENXIO); 23650728Sphk 23752917Sphk while (dp->d_flags & DISKFLAG_LOCK) { 23852917Sphk dp->d_flags |= DISKFLAG_WANTED; 23954815Sphk error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz); 24054815Sphk if (error) 24154815Sphk return (error); 24252917Sphk } 24352917Sphk dp->d_flags |= DISKFLAG_LOCK; 24452917Sphk 24551860Sphk if (!dsisopen(dp->d_slice)) { 24651878Ssos if (!pdev->si_iosize_max) 24751878Ssos pdev->si_iosize_max = dev->si_iosize_max; 24851826Sphk error = dp->d_devsw->d_open(pdev, oflags, devtype, p); 24951860Sphk } 25051826Sphk 25151826Sphk /* Inherit properties from the whole/raw dev_t */ 25262617Simp inherit_raw(pdev, dev); 25350728Sphk 25450728Sphk if (error) 25552917Sphk goto out; 25650728Sphk 25752917Sphk error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label); 25850565Sphk 25950728Sphk if (!dsisopen(dp->d_slice)) 26051924Sphk dp->d_devsw->d_close(pdev, oflags, devtype, p); 26152917Sphkout: 26252917Sphk dp->d_flags &= ~DISKFLAG_LOCK; 26352917Sphk if (dp->d_flags & DISKFLAG_WANTED) { 26452917Sphk dp->d_flags &= ~DISKFLAG_WANTED; 26552917Sphk wakeup(dp); 26652917Sphk } 26750728Sphk 26850565Sphk return(error); 26950565Sphk} 27050565Sphk 27150565Sphkstatic int 27250565Sphkdiskclose(dev_t dev, int fflag, int devtype, struct proc *p) 27350565Sphk{ 27450565Sphk struct disk *dp; 27550565Sphk int error; 27662617Simp dev_t pdev; 27750565Sphk 27850565Sphk error = 0; 27962617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 28062617Simp dp = pdev->si_disk; 28174206Ssos if (!dp) 28274206Ssos return (ENXIO); 28351822Sphk dsclose(dev, devtype, dp->d_slice); 28474206Ssos if (!dsisopen(dp->d_slice)) 28551924Sphk error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p); 28650565Sphk return (error); 28750565Sphk} 28850565Sphk 28950565Sphkstatic void 29059249Sphkdiskstrategy(struct bio *bp) 29150565Sphk{ 29250565Sphk dev_t pdev; 29350565Sphk struct disk *dp; 29450565Sphk 29562617Simp pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART); 29662617Simp dp = pdev->si_disk; 29776361Sphk bp->bio_resid = bp->bio_bcount; 29862617Simp if (dp != bp->bio_dev->si_disk) 29962617Simp inherit_raw(pdev, bp->bio_dev); 30050565Sphk 30150565Sphk if (!dp) { 30276322Sphk biofinish(bp, NULL, ENXIO); 30350565Sphk return; 30450565Sphk } 30550565Sphk 30655763Sphk if (dscheck(bp, dp->d_slice) <= 0) { 30750565Sphk biodone(bp); 30850565Sphk return; 30950565Sphk } 31050565Sphk 31176324Sphk if (bp->bio_bcount == 0) { 31276324Sphk biodone(bp); 31376324Sphk return; 31476324Sphk } 31576324Sphk 31659623Sphk KASSERT(dp->d_devsw != NULL, ("NULL devsw")); 31759623Sphk KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy")); 31851215Sphk dp->d_devsw->d_strategy(bp); 31950565Sphk return; 32050565Sphk 32150565Sphk} 32250565Sphk 32350565Sphkstatic int 32450565Sphkdiskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) 32550565Sphk{ 32650565Sphk struct disk *dp; 32750565Sphk int error; 32862617Simp dev_t pdev; 32950565Sphk 33062617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 33162617Simp dp = pdev->si_disk; 33274206Ssos if (!dp) 33374206Ssos return (ENXIO); 33450565Sphk error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 33550565Sphk if (error == ENOIOCTL) 33651215Sphk error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p); 33750565Sphk return (error); 33850565Sphk} 33950565Sphk 34050565Sphkstatic int 34150565Sphkdiskpsize(dev_t dev) 34250565Sphk{ 34350565Sphk struct disk *dp; 34450728Sphk dev_t pdev; 34550565Sphk 34662617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 34762617Simp dp = pdev->si_disk; 34862617Simp if (!dp) 34962617Simp return (-1); 35062617Simp if (dp != dev->si_disk) { 35150728Sphk dev->si_drv1 = pdev->si_drv1; 35250728Sphk dev->si_drv2 = pdev->si_drv2; 35350728Sphk /* XXX: don't set bp->b_dev->si_disk (?) */ 35450728Sphk } 35550565Sphk return (dssize(dev, &dp->d_slice)); 35650565Sphk} 35751111Sjulian 35851111SjulianSYSCTL_DECL(_debug_sizeof); 35951111Sjulian 36051111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 36151111Sjulian 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 36251111Sjulian 36351111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 36451111Sjulian 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 36551111Sjulian 36651111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 36751111Sjulian 0, sizeof(struct disk), "sizeof(struct disk)"); 368