subr_disk.c revision 92074
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 92074 2002-03-11 08:08:02Z phk $ 1050565Sphk * 1150565Sphk */ 1250565Sphk 1392074Sphk#include "opt_geom.h" 1492074Sphk#ifndef GEOM 1592074Sphk 1650565Sphk#include <sys/param.h> 1750565Sphk#include <sys/systm.h> 1850565Sphk#include <sys/kernel.h> 1951111Sjulian#include <sys/sysctl.h> 2060041Sphk#include <sys/bio.h> 2150565Sphk#include <sys/conf.h> 2250565Sphk#include <sys/disk.h> 2350565Sphk#include <sys/malloc.h> 2461953Snbm#include <sys/sysctl.h> 2550728Sphk#include <machine/md_var.h> 2664880Sphk#include <sys/ctype.h> 2764880Sphk 2869774Sphkstatic MALLOC_DEFINE(M_DISK, "disk", "disk data"); 2950565Sphk 3050565Sphkstatic d_strategy_t diskstrategy; 3150565Sphkstatic d_open_t diskopen; 3250565Sphkstatic d_close_t diskclose; 3350565Sphkstatic d_ioctl_t diskioctl; 3450565Sphkstatic d_psize_t diskpsize; 3561717Sphk 3661717Sphkstatic LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist); 3764880Sphk 3885603Sphkvoid disk_dev_synth(dev_t dev); 3985603Sphk 4085603Sphkvoid 4185603Sphkdisk_dev_synth(dev_t dev) 4285603Sphk{ 4385603Sphk struct disk *dp; 4485603Sphk int u, s, p; 4585603Sphk dev_t pdev; 4685603Sphk 4786012Sphk if (dksparebits(dev)) 4885996Sphk return; 4985603Sphk LIST_FOREACH(dp, &disklist, d_list) { 5085603Sphk if (major(dev) != dp->d_devsw->d_maj) 5185603Sphk continue; 5285603Sphk u = dkunit(dev); 5385603Sphk p = RAW_PART; 5485603Sphk s = WHOLE_DISK_SLICE; 5585603Sphk pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p)); 5685624Sphk if (pdev->si_devsw == NULL) 5785624Sphk return; /* Probably a unit we don't have */ 5885603Sphk s = dkslice(dev); 5985603Sphk p = dkpart(dev); 6085603Sphk if (s == WHOLE_DISK_SLICE && p == RAW_PART) { 6185603Sphk /* XXX: actually should not happen */ 6285603Sphk dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 6385603Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%d", 6485603Sphk dp->d_devsw->d_name, u); 6585603Sphk dev_depends(pdev, dev); 6685603Sphk return; 6785603Sphk } 6885603Sphk if (s == COMPATIBILITY_SLICE) { 6985603Sphk dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 7085603Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%d%c", 7185603Sphk dp->d_devsw->d_name, u, 'a' + p); 7285603Sphk dev_depends(pdev, dev); 7385603Sphk return; 7485603Sphk } 7585858Sphk if (p != RAW_PART) { 7685858Sphk dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 7785858Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c", 7885858Sphk dp->d_devsw->d_name, u, s - BASE_SLICE + 1, 7985858Sphk 'a' + p); 8085858Sphk } else { 8185858Sphk dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 8285858Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d", 8385858Sphk dp->d_devsw->d_name, u, s - BASE_SLICE + 1); 8485858Sphk make_dev_alias(dev, "%s%ds%dc", 8585858Sphk dp->d_devsw->d_name, u, s - BASE_SLICE + 1); 8685858Sphk } 8785603Sphk dev_depends(pdev, dev); 8885603Sphk return; 8985603Sphk } 9085603Sphk} 9185603Sphk 9262617Simpstatic void 9364880Sphkdisk_clone(void *arg, char *name, int namelen, dev_t *dev) 9464880Sphk{ 9564880Sphk struct disk *dp; 9664880Sphk char const *d; 9792074Sphk char *e; 9892074Sphk int j, u, s, p; 9964880Sphk dev_t pdev; 10064880Sphk 10164880Sphk if (*dev != NODEV) 10264880Sphk return; 10364880Sphk 10464880Sphk LIST_FOREACH(dp, &disklist, d_list) { 10564880Sphk d = dp->d_devsw->d_name; 10692074Sphk j = dev_stdclone(name, &e, d, &u); 10792074Sphk if (j == 0) 10864880Sphk continue; 10970058Sphk if (u > DKMAXUNIT) 11070058Sphk continue; 11164880Sphk p = RAW_PART; 11264880Sphk s = WHOLE_DISK_SLICE; 11364880Sphk pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p)); 11464880Sphk if (pdev->si_disk == NULL) 11564880Sphk continue; 11692074Sphk if (*e != '\0') { 11792074Sphk j = dev_stdclone(e, &e, "s", &s); 11892074Sphk if (j == 0) 11992074Sphk s = COMPATIBILITY_SLICE; 12092074Sphk else if (j == 1 || j == 2) 12164880Sphk s += BASE_SLICE - 1; 12292074Sphk if (!*e) 12392074Sphk ; /* ad0s1 case */ 12492074Sphk else if (e[1] != '\0') 12592074Sphk return; /* can never be a disk name */ 12692074Sphk else if (*e < 'a' || *e > 'h') 12792074Sphk return; /* can never be a disk name */ 12864880Sphk else 12992074Sphk p = *e - 'a'; 13064880Sphk } 13192074Sphk if (s == WHOLE_DISK_SLICE && p == RAW_PART) { 13292074Sphk return; 13392074Sphk } else if (s >= BASE_SLICE && p != RAW_PART) { 13485603Sphk *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 13585603Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c", 13685858Sphk pdev->si_devsw->d_name, u, s - BASE_SLICE + 1, 13785858Sphk p + 'a'); 13885858Sphk } else if (s >= BASE_SLICE) { 13985603Sphk *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 14085858Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d", 14185858Sphk pdev->si_devsw->d_name, u, s - BASE_SLICE + 1); 14285858Sphk make_dev_alias(*dev, "%s%ds%dc", 14385858Sphk pdev->si_devsw->d_name, u, s - BASE_SLICE + 1); 14485858Sphk } else { 14585858Sphk *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 14692074Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%d%c", 14792074Sphk pdev->si_devsw->d_name, u, p + 'a'); 14885858Sphk } 14977215Sphk dev_depends(pdev, *dev); 15064880Sphk return; 15164880Sphk } 15264880Sphk} 15364880Sphk 15464880Sphkstatic void 15562617Simpinherit_raw(dev_t pdev, dev_t dev) 15662617Simp{ 15762617Simp dev->si_disk = pdev->si_disk; 15862617Simp dev->si_drv1 = pdev->si_drv1; 15962617Simp dev->si_drv2 = pdev->si_drv2; 16062617Simp dev->si_iosize_max = pdev->si_iosize_max; 16162617Simp dev->si_bsize_phys = pdev->si_bsize_phys; 16262617Simp dev->si_bsize_best = pdev->si_bsize_best; 16362617Simp} 16462617Simp 16550565Sphkdev_t 16651215Sphkdisk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto) 16750565Sphk{ 16864880Sphk static int once; 16977408Sphk dev_t dev; 17050565Sphk 17177215Sphk if (!once) { 17277215Sphk EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000); 17377215Sphk once++; 17477215Sphk } 17577215Sphk 17651198Sphk bzero(dp, sizeof(*dp)); 17751198Sphk 17877147Sphk if (proto->d_open != diskopen) { 17951215Sphk *proto = *cdevsw; 18051215Sphk proto->d_open = diskopen; 18151215Sphk proto->d_close = diskclose; 18251215Sphk proto->d_ioctl = diskioctl; 18351215Sphk proto->d_strategy = diskstrategy; 18451215Sphk proto->d_psize = diskpsize; 18550565Sphk } 18650565Sphk 18753437Sjkh if (bootverbose) 18853437Sjkh printf("Creating DISK %s%d\n", cdevsw->d_name, unit); 18951243Sphk dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART), 19064880Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit); 19150565Sphk 19250565Sphk dev->si_disk = dp; 19350565Sphk dp->d_dev = dev; 19452917Sphk dp->d_dsflags = flags; 19551215Sphk dp->d_devsw = cdevsw; 19661717Sphk LIST_INSERT_HEAD(&disklist, dp, d_list); 19777215Sphk 19850565Sphk return (dev); 19950565Sphk} 20050565Sphk 20150728Sphkint 20250728Sphkdisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize) 20350728Sphk{ 20450728Sphk struct disk *dp; 20550728Sphk struct disklabel *dl; 20650728Sphk u_int boff; 20750728Sphk 20850728Sphk dp = dev->si_disk; 20950728Sphk if (!dp) 21050728Sphk return (ENXIO); 21150728Sphk if (!dp->d_slice) 21250728Sphk return (ENXIO); 21350728Sphk dl = dsgetlabel(dev, dp->d_slice); 21450728Sphk if (!dl) 21550728Sphk return (ENXIO); 21681688Sbde *count = Maxmem * (PAGE_SIZE / dl->d_secsize); 21781688Sbde if (dumplo <= LABELSECTOR || 21850728Sphk (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size)) 21950728Sphk return (EINVAL); 22050728Sphk boff = dl->d_partitions[dkpart(dev)].p_offset + 22150728Sphk dp->d_slice->dss_slices[dkslice(dev)].ds_offset; 22250728Sphk *blkno = boff + dumplo; 22350728Sphk *secsize = dl->d_secsize; 22450728Sphk return (0); 22550728Sphk 22650728Sphk} 22750728Sphk 22850728Sphkvoid 22950728Sphkdisk_invalidate (struct disk *disk) 23050728Sphk{ 23157325Ssos if (disk->d_slice) 23257325Ssos dsgone(&disk->d_slice); 23350728Sphk} 23450728Sphk 23550565Sphkvoid 23656767Sphkdisk_destroy(dev_t dev) 23750565Sphk{ 23861717Sphk LIST_REMOVE(dev->si_disk, d_list); 23961717Sphk bzero(dev->si_disk, sizeof(*dev->si_disk)); 24057325Ssos dev->si_disk = NULL; 24157325Ssos destroy_dev(dev); 24250565Sphk return; 24350565Sphk} 24450565Sphk 24561717Sphkstruct disk * 24661717Sphkdisk_enumerate(struct disk *disk) 24761717Sphk{ 24861717Sphk if (!disk) 24961717Sphk return (LIST_FIRST(&disklist)); 25061717Sphk else 25161717Sphk return (LIST_NEXT(disk, d_list)); 25261717Sphk} 25361717Sphk 25461953Snbmstatic int 25562573Sphksysctl_disks(SYSCTL_HANDLER_ARGS) 25661953Snbm{ 25761953Snbm struct disk *disk; 25861953Snbm int error, first; 25961953Snbm 26061953Snbm disk = NULL; 26161953Snbm first = 1; 26261953Snbm 26361953Snbm while ((disk = disk_enumerate(disk))) { 26461953Snbm if (!first) { 26561953Snbm error = SYSCTL_OUT(req, " ", 1); 26661953Snbm if (error) 26761953Snbm return error; 26861953Snbm } else { 26961953Snbm first = 0; 27061953Snbm } 27161953Snbm error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name)); 27261953Snbm if (error) 27361953Snbm return error; 27461953Snbm } 27561953Snbm error = SYSCTL_OUT(req, "", 1); 27661953Snbm return error; 27761953Snbm} 27861953Snbm 27961953SnbmSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL, 28061953Snbm sysctl_disks, "A", "names of available disks"); 28161953Snbm 28250728Sphk/* 28350728Sphk * The cdevsw functions 28450728Sphk */ 28550728Sphk 28650565Sphkstatic int 28783366Sjuliandiskopen(dev_t dev, int oflags, int devtype, struct thread *td) 28850565Sphk{ 28950565Sphk dev_t pdev; 29050565Sphk struct disk *dp; 29150565Sphk int error; 29250565Sphk 29350728Sphk error = 0; 29450565Sphk pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 29550728Sphk 29650565Sphk dp = pdev->si_disk; 29750565Sphk if (!dp) 29850565Sphk return (ENXIO); 29950728Sphk 30052917Sphk while (dp->d_flags & DISKFLAG_LOCK) { 30152917Sphk dp->d_flags |= DISKFLAG_WANTED; 30254815Sphk error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz); 30354815Sphk if (error) 30454815Sphk return (error); 30552917Sphk } 30652917Sphk dp->d_flags |= DISKFLAG_LOCK; 30752917Sphk 30851860Sphk if (!dsisopen(dp->d_slice)) { 30951878Ssos if (!pdev->si_iosize_max) 31051878Ssos pdev->si_iosize_max = dev->si_iosize_max; 31183366Sjulian error = dp->d_devsw->d_open(pdev, oflags, devtype, td); 31251860Sphk } 31351826Sphk 31451826Sphk /* Inherit properties from the whole/raw dev_t */ 31562617Simp inherit_raw(pdev, dev); 31650728Sphk 31750728Sphk if (error) 31852917Sphk goto out; 31950728Sphk 32052917Sphk error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label); 32150565Sphk 32250728Sphk if (!dsisopen(dp->d_slice)) 32383366Sjulian dp->d_devsw->d_close(pdev, oflags, devtype, td); 32452917Sphkout: 32552917Sphk dp->d_flags &= ~DISKFLAG_LOCK; 32652917Sphk if (dp->d_flags & DISKFLAG_WANTED) { 32752917Sphk dp->d_flags &= ~DISKFLAG_WANTED; 32852917Sphk wakeup(dp); 32952917Sphk } 33050728Sphk 33150565Sphk return(error); 33250565Sphk} 33350565Sphk 33450565Sphkstatic int 33583366Sjuliandiskclose(dev_t dev, int fflag, int devtype, struct thread *td) 33650565Sphk{ 33750565Sphk struct disk *dp; 33850565Sphk int error; 33962617Simp dev_t pdev; 34050565Sphk 34150565Sphk error = 0; 34262617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 34362617Simp dp = pdev->si_disk; 34474206Ssos if (!dp) 34574206Ssos return (ENXIO); 34651822Sphk dsclose(dev, devtype, dp->d_slice); 34774206Ssos if (!dsisopen(dp->d_slice)) 34883366Sjulian error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, td); 34950565Sphk return (error); 35050565Sphk} 35150565Sphk 35250565Sphkstatic void 35359249Sphkdiskstrategy(struct bio *bp) 35450565Sphk{ 35550565Sphk dev_t pdev; 35650565Sphk struct disk *dp; 35750565Sphk 35862617Simp pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART); 35962617Simp dp = pdev->si_disk; 36076361Sphk bp->bio_resid = bp->bio_bcount; 36162617Simp if (dp != bp->bio_dev->si_disk) 36262617Simp inherit_raw(pdev, bp->bio_dev); 36350565Sphk 36450565Sphk if (!dp) { 36576322Sphk biofinish(bp, NULL, ENXIO); 36650565Sphk return; 36750565Sphk } 36850565Sphk 36955763Sphk if (dscheck(bp, dp->d_slice) <= 0) { 37050565Sphk biodone(bp); 37150565Sphk return; 37250565Sphk } 37350565Sphk 37476324Sphk if (bp->bio_bcount == 0) { 37576324Sphk biodone(bp); 37676324Sphk return; 37776324Sphk } 37876324Sphk 37959623Sphk KASSERT(dp->d_devsw != NULL, ("NULL devsw")); 38059623Sphk KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy")); 38151215Sphk dp->d_devsw->d_strategy(bp); 38250565Sphk return; 38350565Sphk 38450565Sphk} 38550565Sphk 38650565Sphkstatic int 38783366Sjuliandiskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 38850565Sphk{ 38950565Sphk struct disk *dp; 39050565Sphk int error; 39162617Simp dev_t pdev; 39250565Sphk 39362617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 39462617Simp dp = pdev->si_disk; 39574206Ssos if (!dp) 39674206Ssos return (ENXIO); 39750565Sphk error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 39850565Sphk if (error == ENOIOCTL) 39983366Sjulian error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, td); 40050565Sphk return (error); 40150565Sphk} 40250565Sphk 40350565Sphkstatic int 40450565Sphkdiskpsize(dev_t dev) 40550565Sphk{ 40650565Sphk struct disk *dp; 40750728Sphk dev_t pdev; 40850565Sphk 40962617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 41062617Simp dp = pdev->si_disk; 41162617Simp if (!dp) 41262617Simp return (-1); 41362617Simp if (dp != dev->si_disk) { 41450728Sphk dev->si_drv1 = pdev->si_drv1; 41550728Sphk dev->si_drv2 = pdev->si_drv2; 41650728Sphk /* XXX: don't set bp->b_dev->si_disk (?) */ 41750728Sphk } 41850565Sphk return (dssize(dev, &dp->d_slice)); 41950565Sphk} 42051111Sjulian 42151111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 42251111Sjulian 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 42351111Sjulian 42451111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 42551111Sjulian 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 42651111Sjulian 42751111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 42851111Sjulian 0, sizeof(struct disk), "sizeof(struct disk)"); 42992074Sphk 43092074Sphk#endif 431