subr_disk.c revision 83366
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 83366 2001-09-12 08:38:13Z julian $ 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); 8977215Sphk dev_depends(pdev, *dev); 9064880Sphk return; 9164880Sphk } 9264880Sphk} 9364880Sphk 9464880Sphkstatic void 9562617Simpinherit_raw(dev_t pdev, dev_t dev) 9662617Simp{ 9762617Simp dev->si_disk = pdev->si_disk; 9862617Simp dev->si_drv1 = pdev->si_drv1; 9962617Simp dev->si_drv2 = pdev->si_drv2; 10062617Simp dev->si_iosize_max = pdev->si_iosize_max; 10162617Simp dev->si_bsize_phys = pdev->si_bsize_phys; 10262617Simp dev->si_bsize_best = pdev->si_bsize_best; 10362617Simp} 10462617Simp 10550565Sphkdev_t 10651215Sphkdisk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto) 10750565Sphk{ 10864880Sphk static int once; 10977408Sphk dev_t dev; 11050565Sphk 11177215Sphk if (!once) { 11277215Sphk EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000); 11377215Sphk once++; 11477215Sphk } 11577215Sphk 11651198Sphk bzero(dp, sizeof(*dp)); 11751198Sphk 11877147Sphk if (proto->d_open != diskopen) { 11951215Sphk *proto = *cdevsw; 12051215Sphk proto->d_open = diskopen; 12151215Sphk proto->d_close = diskclose; 12251215Sphk proto->d_ioctl = diskioctl; 12351215Sphk proto->d_strategy = diskstrategy; 12451215Sphk proto->d_psize = diskpsize; 12577343Sphk cdevsw_add(proto); 12650565Sphk } 12750565Sphk 12853437Sjkh if (bootverbose) 12953437Sjkh printf("Creating DISK %s%d\n", cdevsw->d_name, unit); 13051243Sphk dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART), 13164880Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit); 13250565Sphk 13350565Sphk dev->si_disk = dp; 13450565Sphk dp->d_dev = dev; 13552917Sphk dp->d_dsflags = flags; 13651215Sphk dp->d_devsw = cdevsw; 13761717Sphk LIST_INSERT_HEAD(&disklist, dp, d_list); 13877215Sphk 13950565Sphk return (dev); 14050565Sphk} 14150565Sphk 14250728Sphkint 14350728Sphkdisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize) 14450728Sphk{ 14550728Sphk struct disk *dp; 14650728Sphk struct disklabel *dl; 14750728Sphk u_int boff; 14850728Sphk 14950728Sphk dp = dev->si_disk; 15050728Sphk if (!dp) 15150728Sphk return (ENXIO); 15250728Sphk if (!dp->d_slice) 15350728Sphk return (ENXIO); 15450728Sphk dl = dsgetlabel(dev, dp->d_slice); 15550728Sphk if (!dl) 15650728Sphk return (ENXIO); 15781688Sbde *count = Maxmem * (PAGE_SIZE / dl->d_secsize); 15881688Sbde if (dumplo <= LABELSECTOR || 15950728Sphk (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size)) 16050728Sphk return (EINVAL); 16150728Sphk boff = dl->d_partitions[dkpart(dev)].p_offset + 16250728Sphk dp->d_slice->dss_slices[dkslice(dev)].ds_offset; 16350728Sphk *blkno = boff + dumplo; 16450728Sphk *secsize = dl->d_secsize; 16550728Sphk return (0); 16650728Sphk 16750728Sphk} 16850728Sphk 16950728Sphkvoid 17050728Sphkdisk_invalidate (struct disk *disk) 17150728Sphk{ 17257325Ssos if (disk->d_slice) 17357325Ssos dsgone(&disk->d_slice); 17450728Sphk} 17550728Sphk 17650565Sphkvoid 17756767Sphkdisk_destroy(dev_t dev) 17850565Sphk{ 17961717Sphk LIST_REMOVE(dev->si_disk, d_list); 18061717Sphk bzero(dev->si_disk, sizeof(*dev->si_disk)); 18157325Ssos dev->si_disk = NULL; 18257325Ssos destroy_dev(dev); 18350565Sphk return; 18450565Sphk} 18550565Sphk 18661717Sphkstruct disk * 18761717Sphkdisk_enumerate(struct disk *disk) 18861717Sphk{ 18961717Sphk if (!disk) 19061717Sphk return (LIST_FIRST(&disklist)); 19161717Sphk else 19261717Sphk return (LIST_NEXT(disk, d_list)); 19361717Sphk} 19461717Sphk 19561953Snbmstatic int 19662573Sphksysctl_disks(SYSCTL_HANDLER_ARGS) 19761953Snbm{ 19861953Snbm struct disk *disk; 19961953Snbm int error, first; 20061953Snbm 20161953Snbm disk = NULL; 20261953Snbm first = 1; 20361953Snbm 20461953Snbm while ((disk = disk_enumerate(disk))) { 20561953Snbm if (!first) { 20661953Snbm error = SYSCTL_OUT(req, " ", 1); 20761953Snbm if (error) 20861953Snbm return error; 20961953Snbm } else { 21061953Snbm first = 0; 21161953Snbm } 21261953Snbm error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name)); 21361953Snbm if (error) 21461953Snbm return error; 21561953Snbm } 21661953Snbm error = SYSCTL_OUT(req, "", 1); 21761953Snbm return error; 21861953Snbm} 21961953Snbm 22061953SnbmSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL, 22161953Snbm sysctl_disks, "A", "names of available disks"); 22261953Snbm 22350728Sphk/* 22450728Sphk * The cdevsw functions 22550728Sphk */ 22650728Sphk 22750565Sphkstatic int 22883366Sjuliandiskopen(dev_t dev, int oflags, int devtype, struct thread *td) 22950565Sphk{ 23050565Sphk dev_t pdev; 23150565Sphk struct disk *dp; 23250565Sphk int error; 23350565Sphk 23450728Sphk error = 0; 23550565Sphk pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 23650728Sphk 23750565Sphk dp = pdev->si_disk; 23850565Sphk if (!dp) 23950565Sphk return (ENXIO); 24050728Sphk 24152917Sphk while (dp->d_flags & DISKFLAG_LOCK) { 24252917Sphk dp->d_flags |= DISKFLAG_WANTED; 24354815Sphk error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz); 24454815Sphk if (error) 24554815Sphk return (error); 24652917Sphk } 24752917Sphk dp->d_flags |= DISKFLAG_LOCK; 24852917Sphk 24951860Sphk if (!dsisopen(dp->d_slice)) { 25051878Ssos if (!pdev->si_iosize_max) 25151878Ssos pdev->si_iosize_max = dev->si_iosize_max; 25283366Sjulian error = dp->d_devsw->d_open(pdev, oflags, devtype, td); 25351860Sphk } 25451826Sphk 25551826Sphk /* Inherit properties from the whole/raw dev_t */ 25662617Simp inherit_raw(pdev, dev); 25750728Sphk 25850728Sphk if (error) 25952917Sphk goto out; 26050728Sphk 26152917Sphk error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label); 26250565Sphk 26350728Sphk if (!dsisopen(dp->d_slice)) 26483366Sjulian dp->d_devsw->d_close(pdev, oflags, devtype, td); 26552917Sphkout: 26652917Sphk dp->d_flags &= ~DISKFLAG_LOCK; 26752917Sphk if (dp->d_flags & DISKFLAG_WANTED) { 26852917Sphk dp->d_flags &= ~DISKFLAG_WANTED; 26952917Sphk wakeup(dp); 27052917Sphk } 27150728Sphk 27250565Sphk return(error); 27350565Sphk} 27450565Sphk 27550565Sphkstatic int 27683366Sjuliandiskclose(dev_t dev, int fflag, int devtype, struct thread *td) 27750565Sphk{ 27850565Sphk struct disk *dp; 27950565Sphk int error; 28062617Simp dev_t pdev; 28150565Sphk 28250565Sphk error = 0; 28362617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 28462617Simp dp = pdev->si_disk; 28574206Ssos if (!dp) 28674206Ssos return (ENXIO); 28751822Sphk dsclose(dev, devtype, dp->d_slice); 28874206Ssos if (!dsisopen(dp->d_slice)) 28983366Sjulian error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, td); 29050565Sphk return (error); 29150565Sphk} 29250565Sphk 29350565Sphkstatic void 29459249Sphkdiskstrategy(struct bio *bp) 29550565Sphk{ 29650565Sphk dev_t pdev; 29750565Sphk struct disk *dp; 29850565Sphk 29962617Simp pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART); 30062617Simp dp = pdev->si_disk; 30176361Sphk bp->bio_resid = bp->bio_bcount; 30262617Simp if (dp != bp->bio_dev->si_disk) 30362617Simp inherit_raw(pdev, bp->bio_dev); 30450565Sphk 30550565Sphk if (!dp) { 30676322Sphk biofinish(bp, NULL, ENXIO); 30750565Sphk return; 30850565Sphk } 30950565Sphk 31055763Sphk if (dscheck(bp, dp->d_slice) <= 0) { 31150565Sphk biodone(bp); 31250565Sphk return; 31350565Sphk } 31450565Sphk 31576324Sphk if (bp->bio_bcount == 0) { 31676324Sphk biodone(bp); 31776324Sphk return; 31876324Sphk } 31976324Sphk 32059623Sphk KASSERT(dp->d_devsw != NULL, ("NULL devsw")); 32159623Sphk KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy")); 32251215Sphk dp->d_devsw->d_strategy(bp); 32350565Sphk return; 32450565Sphk 32550565Sphk} 32650565Sphk 32750565Sphkstatic int 32883366Sjuliandiskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 32950565Sphk{ 33050565Sphk struct disk *dp; 33150565Sphk int error; 33262617Simp dev_t pdev; 33350565Sphk 33462617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 33562617Simp dp = pdev->si_disk; 33674206Ssos if (!dp) 33774206Ssos return (ENXIO); 33850565Sphk error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 33950565Sphk if (error == ENOIOCTL) 34083366Sjulian error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, td); 34150565Sphk return (error); 34250565Sphk} 34350565Sphk 34450565Sphkstatic int 34550565Sphkdiskpsize(dev_t dev) 34650565Sphk{ 34750565Sphk struct disk *dp; 34850728Sphk dev_t pdev; 34950565Sphk 35062617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 35162617Simp dp = pdev->si_disk; 35262617Simp if (!dp) 35362617Simp return (-1); 35462617Simp if (dp != dev->si_disk) { 35550728Sphk dev->si_drv1 = pdev->si_drv1; 35650728Sphk dev->si_drv2 = pdev->si_drv2; 35750728Sphk /* XXX: don't set bp->b_dev->si_disk (?) */ 35850728Sphk } 35950565Sphk return (dssize(dev, &dp->d_slice)); 36050565Sphk} 36151111Sjulian 36251111SjulianSYSCTL_DECL(_debug_sizeof); 36351111Sjulian 36451111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 36551111Sjulian 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 36651111Sjulian 36751111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 36851111Sjulian 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 36951111Sjulian 37051111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 37151111Sjulian 0, sizeof(struct disk), "sizeof(struct disk)"); 372