subr_disk.c revision 76361
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 76361 2001-05-08 08:24:54Z 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 11250565Sphk dev = makedev(cdevsw->d_maj, 0); 11351198Sphk if (!devsw(dev)) { 11451215Sphk *proto = *cdevsw; 11551215Sphk proto->d_open = diskopen; 11651215Sphk proto->d_close = diskclose; 11751215Sphk proto->d_ioctl = diskioctl; 11851215Sphk proto->d_strategy = diskstrategy; 11951215Sphk proto->d_psize = diskpsize; 12051215Sphk cdevsw_add(proto); 12150565Sphk } 12250565Sphk 12353437Sjkh if (bootverbose) 12453437Sjkh printf("Creating DISK %s%d\n", cdevsw->d_name, unit); 12551243Sphk dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART), 12664880Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit); 12750565Sphk 12850565Sphk dev->si_disk = dp; 12950565Sphk dp->d_dev = dev; 13052917Sphk dp->d_dsflags = flags; 13151215Sphk dp->d_devsw = cdevsw; 13261717Sphk LIST_INSERT_HEAD(&disklist, dp, d_list); 13364880Sphk if (!once) { 13465374Sphk EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000); 13564880Sphk once++; 13664880Sphk } 13750565Sphk return (dev); 13850565Sphk} 13950565Sphk 14050728Sphkint 14150728Sphkdisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize) 14250728Sphk{ 14350728Sphk struct disk *dp; 14450728Sphk struct disklabel *dl; 14550728Sphk u_int boff; 14650728Sphk 14750728Sphk dp = dev->si_disk; 14850728Sphk if (!dp) 14950728Sphk return (ENXIO); 15050728Sphk if (!dp->d_slice) 15150728Sphk return (ENXIO); 15250728Sphk dl = dsgetlabel(dev, dp->d_slice); 15350728Sphk if (!dl) 15450728Sphk return (ENXIO); 15550728Sphk *count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize; 15650728Sphk if (dumplo < 0 || 15750728Sphk (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size)) 15850728Sphk return (EINVAL); 15950728Sphk boff = dl->d_partitions[dkpart(dev)].p_offset + 16050728Sphk dp->d_slice->dss_slices[dkslice(dev)].ds_offset; 16150728Sphk *blkno = boff + dumplo; 16250728Sphk *secsize = dl->d_secsize; 16350728Sphk return (0); 16450728Sphk 16550728Sphk} 16650728Sphk 16750728Sphkvoid 16850728Sphkdisk_invalidate (struct disk *disk) 16950728Sphk{ 17057325Ssos if (disk->d_slice) 17157325Ssos dsgone(&disk->d_slice); 17250728Sphk} 17350728Sphk 17450565Sphkvoid 17556767Sphkdisk_destroy(dev_t dev) 17650565Sphk{ 17761717Sphk LIST_REMOVE(dev->si_disk, d_list); 17861717Sphk bzero(dev->si_disk, sizeof(*dev->si_disk)); 17957325Ssos dev->si_disk = NULL; 18057325Ssos destroy_dev(dev); 18150565Sphk return; 18250565Sphk} 18350565Sphk 18461717Sphkstruct disk * 18561717Sphkdisk_enumerate(struct disk *disk) 18661717Sphk{ 18761717Sphk if (!disk) 18861717Sphk return (LIST_FIRST(&disklist)); 18961717Sphk else 19061717Sphk return (LIST_NEXT(disk, d_list)); 19161717Sphk} 19261717Sphk 19361953Snbmstatic int 19462573Sphksysctl_disks(SYSCTL_HANDLER_ARGS) 19561953Snbm{ 19661953Snbm struct disk *disk; 19761953Snbm int error, first; 19861953Snbm 19961953Snbm disk = NULL; 20061953Snbm first = 1; 20161953Snbm 20261953Snbm while ((disk = disk_enumerate(disk))) { 20361953Snbm if (!first) { 20461953Snbm error = SYSCTL_OUT(req, " ", 1); 20561953Snbm if (error) 20661953Snbm return error; 20761953Snbm } else { 20861953Snbm first = 0; 20961953Snbm } 21061953Snbm error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name)); 21161953Snbm if (error) 21261953Snbm return error; 21361953Snbm } 21461953Snbm error = SYSCTL_OUT(req, "", 1); 21561953Snbm return error; 21661953Snbm} 21761953Snbm 21861953SnbmSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL, 21961953Snbm sysctl_disks, "A", "names of available disks"); 22061953Snbm 22150728Sphk/* 22250728Sphk * The cdevsw functions 22350728Sphk */ 22450728Sphk 22550565Sphkstatic int 22650565Sphkdiskopen(dev_t dev, int oflags, int devtype, struct proc *p) 22750565Sphk{ 22850565Sphk dev_t pdev; 22950565Sphk struct disk *dp; 23050565Sphk int error; 23150565Sphk 23250728Sphk error = 0; 23350565Sphk pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 23450728Sphk 23550565Sphk dp = pdev->si_disk; 23650565Sphk if (!dp) 23750565Sphk return (ENXIO); 23850728Sphk 23952917Sphk while (dp->d_flags & DISKFLAG_LOCK) { 24052917Sphk dp->d_flags |= DISKFLAG_WANTED; 24154815Sphk error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz); 24254815Sphk if (error) 24354815Sphk return (error); 24452917Sphk } 24552917Sphk dp->d_flags |= DISKFLAG_LOCK; 24652917Sphk 24751860Sphk if (!dsisopen(dp->d_slice)) { 24851878Ssos if (!pdev->si_iosize_max) 24951878Ssos pdev->si_iosize_max = dev->si_iosize_max; 25051826Sphk error = dp->d_devsw->d_open(pdev, oflags, devtype, p); 25151860Sphk } 25251826Sphk 25351826Sphk /* Inherit properties from the whole/raw dev_t */ 25462617Simp inherit_raw(pdev, dev); 25550728Sphk 25650728Sphk if (error) 25752917Sphk goto out; 25850728Sphk 25952917Sphk error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label); 26050565Sphk 26150728Sphk if (!dsisopen(dp->d_slice)) 26251924Sphk dp->d_devsw->d_close(pdev, oflags, devtype, p); 26352917Sphkout: 26452917Sphk dp->d_flags &= ~DISKFLAG_LOCK; 26552917Sphk if (dp->d_flags & DISKFLAG_WANTED) { 26652917Sphk dp->d_flags &= ~DISKFLAG_WANTED; 26752917Sphk wakeup(dp); 26852917Sphk } 26950728Sphk 27050565Sphk return(error); 27150565Sphk} 27250565Sphk 27350565Sphkstatic int 27450565Sphkdiskclose(dev_t dev, int fflag, int devtype, struct proc *p) 27550565Sphk{ 27650565Sphk struct disk *dp; 27750565Sphk int error; 27862617Simp dev_t pdev; 27950565Sphk 28050565Sphk error = 0; 28162617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 28262617Simp dp = pdev->si_disk; 28374206Ssos if (!dp) 28474206Ssos return (ENXIO); 28551822Sphk dsclose(dev, devtype, dp->d_slice); 28674206Ssos if (!dsisopen(dp->d_slice)) 28751924Sphk error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p); 28850565Sphk return (error); 28950565Sphk} 29050565Sphk 29150565Sphkstatic void 29259249Sphkdiskstrategy(struct bio *bp) 29350565Sphk{ 29450565Sphk dev_t pdev; 29550565Sphk struct disk *dp; 29650565Sphk 29762617Simp pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART); 29862617Simp dp = pdev->si_disk; 29976361Sphk bp->bio_resid = bp->bio_bcount; 30062617Simp if (dp != bp->bio_dev->si_disk) 30162617Simp inherit_raw(pdev, bp->bio_dev); 30250565Sphk 30350565Sphk if (!dp) { 30476322Sphk biofinish(bp, NULL, ENXIO); 30550565Sphk return; 30650565Sphk } 30750565Sphk 30855763Sphk if (dscheck(bp, dp->d_slice) <= 0) { 30950565Sphk biodone(bp); 31050565Sphk return; 31150565Sphk } 31250565Sphk 31376324Sphk if (bp->bio_bcount == 0) { 31476324Sphk biodone(bp); 31576324Sphk return; 31676324Sphk } 31776324Sphk 31859623Sphk KASSERT(dp->d_devsw != NULL, ("NULL devsw")); 31959623Sphk KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy")); 32051215Sphk dp->d_devsw->d_strategy(bp); 32150565Sphk return; 32250565Sphk 32350565Sphk} 32450565Sphk 32550565Sphkstatic int 32650565Sphkdiskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) 32750565Sphk{ 32850565Sphk struct disk *dp; 32950565Sphk int error; 33062617Simp dev_t pdev; 33150565Sphk 33262617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 33362617Simp dp = pdev->si_disk; 33474206Ssos if (!dp) 33574206Ssos return (ENXIO); 33650565Sphk error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 33750565Sphk if (error == ENOIOCTL) 33851215Sphk error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p); 33950565Sphk return (error); 34050565Sphk} 34150565Sphk 34250565Sphkstatic int 34350565Sphkdiskpsize(dev_t dev) 34450565Sphk{ 34550565Sphk struct disk *dp; 34650728Sphk dev_t pdev; 34750565Sphk 34862617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 34962617Simp dp = pdev->si_disk; 35062617Simp if (!dp) 35162617Simp return (-1); 35262617Simp if (dp != dev->si_disk) { 35350728Sphk dev->si_drv1 = pdev->si_drv1; 35450728Sphk dev->si_drv2 = pdev->si_drv2; 35550728Sphk /* XXX: don't set bp->b_dev->si_disk (?) */ 35650728Sphk } 35750565Sphk return (dssize(dev, &dp->d_slice)); 35850565Sphk} 35951111Sjulian 36051111SjulianSYSCTL_DECL(_debug_sizeof); 36151111Sjulian 36251111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 36351111Sjulian 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 36451111Sjulian 36551111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 36651111Sjulian 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 36751111Sjulian 36851111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 36951111Sjulian 0, sizeof(struct disk), "sizeof(struct disk)"); 370