subr_disk.c revision 85996
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 85996 2001-11-03 23:21:00Z 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 3585603Sphkvoid disk_dev_synth(dev_t dev); 3685603Sphk 3785603Sphkvoid 3885603Sphkdisk_dev_synth(dev_t dev) 3985603Sphk{ 4085603Sphk struct disk *dp; 4185603Sphk int u, s, p; 4285603Sphk dev_t pdev; 4385603Sphk 4485996Sphk if (dktype(dev)) 4585996Sphk return; 4685603Sphk LIST_FOREACH(dp, &disklist, d_list) { 4785603Sphk if (major(dev) != dp->d_devsw->d_maj) 4885603Sphk continue; 4985603Sphk u = dkunit(dev); 5085603Sphk p = RAW_PART; 5185603Sphk s = WHOLE_DISK_SLICE; 5285603Sphk pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p)); 5385624Sphk if (pdev->si_devsw == NULL) 5485624Sphk return; /* Probably a unit we don't have */ 5585603Sphk s = dkslice(dev); 5685603Sphk p = dkpart(dev); 5785603Sphk if (s == WHOLE_DISK_SLICE && p == RAW_PART) { 5885603Sphk /* XXX: actually should not happen */ 5985603Sphk dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 6085603Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%d", 6185603Sphk dp->d_devsw->d_name, u); 6285603Sphk dev_depends(pdev, dev); 6385603Sphk return; 6485603Sphk } 6585603Sphk if (s == COMPATIBILITY_SLICE) { 6685603Sphk dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 6785603Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%d%c", 6885603Sphk dp->d_devsw->d_name, u, 'a' + p); 6985603Sphk dev_depends(pdev, dev); 7085603Sphk return; 7185603Sphk } 7285858Sphk if (p != RAW_PART) { 7385858Sphk dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 7485858Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c", 7585858Sphk dp->d_devsw->d_name, u, s - BASE_SLICE + 1, 7685858Sphk 'a' + p); 7785858Sphk } else { 7885858Sphk dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 7985858Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d", 8085858Sphk dp->d_devsw->d_name, u, s - BASE_SLICE + 1); 8185858Sphk make_dev_alias(dev, "%s%ds%dc", 8285858Sphk dp->d_devsw->d_name, u, s - BASE_SLICE + 1); 8385858Sphk } 8485603Sphk dev_depends(pdev, dev); 8585603Sphk return; 8685603Sphk } 8785603Sphk} 8885603Sphk 8962617Simpstatic void 9064880Sphkdisk_clone(void *arg, char *name, int namelen, dev_t *dev) 9164880Sphk{ 9264880Sphk struct disk *dp; 9364880Sphk char const *d; 9464880Sphk int i, u, s, p; 9564880Sphk dev_t pdev; 9664880Sphk 9764880Sphk if (*dev != NODEV) 9864880Sphk return; 9964880Sphk 10064880Sphk LIST_FOREACH(dp, &disklist, d_list) { 10164880Sphk d = dp->d_devsw->d_name; 10264880Sphk i = strlen(d); 10364880Sphk if (bcmp(d, name, i) != 0) 10464880Sphk continue; 10564880Sphk u = 0; 10664880Sphk if (!isdigit(name[i])) 10764880Sphk continue; 10864880Sphk while (isdigit(name[i])) { 10964880Sphk u *= 10; 11064880Sphk u += name[i++] - '0'; 11164880Sphk } 11270058Sphk if (u > DKMAXUNIT) 11370058Sphk continue; 11464880Sphk p = RAW_PART; 11564880Sphk s = WHOLE_DISK_SLICE; 11664880Sphk pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p)); 11764880Sphk if (pdev->si_disk == NULL) 11864880Sphk continue; 11964880Sphk if (name[i] != '\0') { 12064880Sphk if (name[i] == 's') { 12164880Sphk s = 0; 12264880Sphk i++; 12364880Sphk if (!isdigit(name[i])) 12464880Sphk continue; 12564880Sphk while (isdigit(name[i])) { 12664880Sphk s *= 10; 12764880Sphk s += name[i++] - '0'; 12864880Sphk } 12964880Sphk s += BASE_SLICE - 1; 13064880Sphk } else { 13164880Sphk s = COMPATIBILITY_SLICE; 13264880Sphk } 13364880Sphk if (name[i] == '\0') 13464880Sphk ; 13585311Sphk else if (name[i + 1] != '\0') 13685311Sphk return; 13764880Sphk else if (name[i] < 'a' || name[i] > 'h') 13864880Sphk continue; 13964880Sphk else 14064880Sphk p = name[i] - 'a'; 14164880Sphk } 14264880Sphk 14385858Sphk if (s >= BASE_SLICE && p != RAW_PART) { 14485603Sphk *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 14585603Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c", 14685858Sphk pdev->si_devsw->d_name, u, s - BASE_SLICE + 1, 14785858Sphk p + 'a'); 14885858Sphk } else if (s >= BASE_SLICE) { 14985603Sphk *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 15085858Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d", 15185858Sphk pdev->si_devsw->d_name, u, s - BASE_SLICE + 1); 15285858Sphk make_dev_alias(*dev, "%s%ds%dc", 15385858Sphk pdev->si_devsw->d_name, u, s - BASE_SLICE + 1); 15485858Sphk } else { 15585858Sphk *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 15685603Sphk UID_ROOT, GID_OPERATOR, 0640, name); 15785858Sphk } 15877215Sphk dev_depends(pdev, *dev); 15964880Sphk return; 16064880Sphk } 16164880Sphk} 16264880Sphk 16364880Sphkstatic void 16462617Simpinherit_raw(dev_t pdev, dev_t dev) 16562617Simp{ 16662617Simp dev->si_disk = pdev->si_disk; 16762617Simp dev->si_drv1 = pdev->si_drv1; 16862617Simp dev->si_drv2 = pdev->si_drv2; 16962617Simp dev->si_iosize_max = pdev->si_iosize_max; 17062617Simp dev->si_bsize_phys = pdev->si_bsize_phys; 17162617Simp dev->si_bsize_best = pdev->si_bsize_best; 17262617Simp} 17362617Simp 17450565Sphkdev_t 17551215Sphkdisk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto) 17650565Sphk{ 17764880Sphk static int once; 17877408Sphk dev_t dev; 17950565Sphk 18077215Sphk if (!once) { 18177215Sphk EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000); 18277215Sphk once++; 18377215Sphk } 18477215Sphk 18551198Sphk bzero(dp, sizeof(*dp)); 18651198Sphk 18777147Sphk if (proto->d_open != diskopen) { 18851215Sphk *proto = *cdevsw; 18951215Sphk proto->d_open = diskopen; 19051215Sphk proto->d_close = diskclose; 19151215Sphk proto->d_ioctl = diskioctl; 19251215Sphk proto->d_strategy = diskstrategy; 19351215Sphk proto->d_psize = diskpsize; 19477343Sphk cdevsw_add(proto); 19550565Sphk } 19650565Sphk 19753437Sjkh if (bootverbose) 19853437Sjkh printf("Creating DISK %s%d\n", cdevsw->d_name, unit); 19951243Sphk dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART), 20064880Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit); 20150565Sphk 20250565Sphk dev->si_disk = dp; 20350565Sphk dp->d_dev = dev; 20452917Sphk dp->d_dsflags = flags; 20551215Sphk dp->d_devsw = cdevsw; 20661717Sphk LIST_INSERT_HEAD(&disklist, dp, d_list); 20777215Sphk 20850565Sphk return (dev); 20950565Sphk} 21050565Sphk 21150728Sphkint 21250728Sphkdisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize) 21350728Sphk{ 21450728Sphk struct disk *dp; 21550728Sphk struct disklabel *dl; 21650728Sphk u_int boff; 21750728Sphk 21850728Sphk dp = dev->si_disk; 21950728Sphk if (!dp) 22050728Sphk return (ENXIO); 22150728Sphk if (!dp->d_slice) 22250728Sphk return (ENXIO); 22350728Sphk dl = dsgetlabel(dev, dp->d_slice); 22450728Sphk if (!dl) 22550728Sphk return (ENXIO); 22681688Sbde *count = Maxmem * (PAGE_SIZE / dl->d_secsize); 22781688Sbde if (dumplo <= LABELSECTOR || 22850728Sphk (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size)) 22950728Sphk return (EINVAL); 23050728Sphk boff = dl->d_partitions[dkpart(dev)].p_offset + 23150728Sphk dp->d_slice->dss_slices[dkslice(dev)].ds_offset; 23250728Sphk *blkno = boff + dumplo; 23350728Sphk *secsize = dl->d_secsize; 23450728Sphk return (0); 23550728Sphk 23650728Sphk} 23750728Sphk 23850728Sphkvoid 23950728Sphkdisk_invalidate (struct disk *disk) 24050728Sphk{ 24157325Ssos if (disk->d_slice) 24257325Ssos dsgone(&disk->d_slice); 24350728Sphk} 24450728Sphk 24550565Sphkvoid 24656767Sphkdisk_destroy(dev_t dev) 24750565Sphk{ 24861717Sphk LIST_REMOVE(dev->si_disk, d_list); 24961717Sphk bzero(dev->si_disk, sizeof(*dev->si_disk)); 25057325Ssos dev->si_disk = NULL; 25157325Ssos destroy_dev(dev); 25250565Sphk return; 25350565Sphk} 25450565Sphk 25561717Sphkstruct disk * 25661717Sphkdisk_enumerate(struct disk *disk) 25761717Sphk{ 25861717Sphk if (!disk) 25961717Sphk return (LIST_FIRST(&disklist)); 26061717Sphk else 26161717Sphk return (LIST_NEXT(disk, d_list)); 26261717Sphk} 26361717Sphk 26461953Snbmstatic int 26562573Sphksysctl_disks(SYSCTL_HANDLER_ARGS) 26661953Snbm{ 26761953Snbm struct disk *disk; 26861953Snbm int error, first; 26961953Snbm 27061953Snbm disk = NULL; 27161953Snbm first = 1; 27261953Snbm 27361953Snbm while ((disk = disk_enumerate(disk))) { 27461953Snbm if (!first) { 27561953Snbm error = SYSCTL_OUT(req, " ", 1); 27661953Snbm if (error) 27761953Snbm return error; 27861953Snbm } else { 27961953Snbm first = 0; 28061953Snbm } 28161953Snbm error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name)); 28261953Snbm if (error) 28361953Snbm return error; 28461953Snbm } 28561953Snbm error = SYSCTL_OUT(req, "", 1); 28661953Snbm return error; 28761953Snbm} 28861953Snbm 28961953SnbmSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL, 29061953Snbm sysctl_disks, "A", "names of available disks"); 29161953Snbm 29250728Sphk/* 29350728Sphk * The cdevsw functions 29450728Sphk */ 29550728Sphk 29650565Sphkstatic int 29783366Sjuliandiskopen(dev_t dev, int oflags, int devtype, struct thread *td) 29850565Sphk{ 29950565Sphk dev_t pdev; 30050565Sphk struct disk *dp; 30150565Sphk int error; 30250565Sphk 30350728Sphk error = 0; 30450565Sphk pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 30550728Sphk 30650565Sphk dp = pdev->si_disk; 30750565Sphk if (!dp) 30850565Sphk return (ENXIO); 30950728Sphk 31052917Sphk while (dp->d_flags & DISKFLAG_LOCK) { 31152917Sphk dp->d_flags |= DISKFLAG_WANTED; 31254815Sphk error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz); 31354815Sphk if (error) 31454815Sphk return (error); 31552917Sphk } 31652917Sphk dp->d_flags |= DISKFLAG_LOCK; 31752917Sphk 31851860Sphk if (!dsisopen(dp->d_slice)) { 31951878Ssos if (!pdev->si_iosize_max) 32051878Ssos pdev->si_iosize_max = dev->si_iosize_max; 32183366Sjulian error = dp->d_devsw->d_open(pdev, oflags, devtype, td); 32251860Sphk } 32351826Sphk 32451826Sphk /* Inherit properties from the whole/raw dev_t */ 32562617Simp inherit_raw(pdev, dev); 32650728Sphk 32750728Sphk if (error) 32852917Sphk goto out; 32950728Sphk 33052917Sphk error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label); 33150565Sphk 33250728Sphk if (!dsisopen(dp->d_slice)) 33383366Sjulian dp->d_devsw->d_close(pdev, oflags, devtype, td); 33452917Sphkout: 33552917Sphk dp->d_flags &= ~DISKFLAG_LOCK; 33652917Sphk if (dp->d_flags & DISKFLAG_WANTED) { 33752917Sphk dp->d_flags &= ~DISKFLAG_WANTED; 33852917Sphk wakeup(dp); 33952917Sphk } 34050728Sphk 34150565Sphk return(error); 34250565Sphk} 34350565Sphk 34450565Sphkstatic int 34583366Sjuliandiskclose(dev_t dev, int fflag, int devtype, struct thread *td) 34650565Sphk{ 34750565Sphk struct disk *dp; 34850565Sphk int error; 34962617Simp dev_t pdev; 35050565Sphk 35150565Sphk error = 0; 35262617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 35362617Simp dp = pdev->si_disk; 35474206Ssos if (!dp) 35574206Ssos return (ENXIO); 35651822Sphk dsclose(dev, devtype, dp->d_slice); 35774206Ssos if (!dsisopen(dp->d_slice)) 35883366Sjulian error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, td); 35950565Sphk return (error); 36050565Sphk} 36150565Sphk 36250565Sphkstatic void 36359249Sphkdiskstrategy(struct bio *bp) 36450565Sphk{ 36550565Sphk dev_t pdev; 36650565Sphk struct disk *dp; 36750565Sphk 36862617Simp pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART); 36962617Simp dp = pdev->si_disk; 37076361Sphk bp->bio_resid = bp->bio_bcount; 37162617Simp if (dp != bp->bio_dev->si_disk) 37262617Simp inherit_raw(pdev, bp->bio_dev); 37350565Sphk 37450565Sphk if (!dp) { 37576322Sphk biofinish(bp, NULL, ENXIO); 37650565Sphk return; 37750565Sphk } 37850565Sphk 37955763Sphk if (dscheck(bp, dp->d_slice) <= 0) { 38050565Sphk biodone(bp); 38150565Sphk return; 38250565Sphk } 38350565Sphk 38476324Sphk if (bp->bio_bcount == 0) { 38576324Sphk biodone(bp); 38676324Sphk return; 38776324Sphk } 38876324Sphk 38959623Sphk KASSERT(dp->d_devsw != NULL, ("NULL devsw")); 39059623Sphk KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy")); 39151215Sphk dp->d_devsw->d_strategy(bp); 39250565Sphk return; 39350565Sphk 39450565Sphk} 39550565Sphk 39650565Sphkstatic int 39783366Sjuliandiskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 39850565Sphk{ 39950565Sphk struct disk *dp; 40050565Sphk int error; 40162617Simp dev_t pdev; 40250565Sphk 40362617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 40462617Simp dp = pdev->si_disk; 40574206Ssos if (!dp) 40674206Ssos return (ENXIO); 40750565Sphk error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 40850565Sphk if (error == ENOIOCTL) 40983366Sjulian error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, td); 41050565Sphk return (error); 41150565Sphk} 41250565Sphk 41350565Sphkstatic int 41450565Sphkdiskpsize(dev_t dev) 41550565Sphk{ 41650565Sphk struct disk *dp; 41750728Sphk dev_t pdev; 41850565Sphk 41962617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 42062617Simp dp = pdev->si_disk; 42162617Simp if (!dp) 42262617Simp return (-1); 42362617Simp if (dp != dev->si_disk) { 42450728Sphk dev->si_drv1 = pdev->si_drv1; 42550728Sphk dev->si_drv2 = pdev->si_drv2; 42650728Sphk /* XXX: don't set bp->b_dev->si_disk (?) */ 42750728Sphk } 42850565Sphk return (dssize(dev, &dp->d_slice)); 42950565Sphk} 43051111Sjulian 43151111SjulianSYSCTL_DECL(_debug_sizeof); 43251111Sjulian 43351111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 43451111Sjulian 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 43551111Sjulian 43651111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 43751111Sjulian 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 43851111Sjulian 43951111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 44051111Sjulian 0, sizeof(struct disk), "sizeof(struct disk)"); 441