subr_disk.c revision 85603
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 85603 2001-10-27 17:44:21Z 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 4485603Sphk LIST_FOREACH(dp, &disklist, d_list) { 4585603Sphk if (major(dev) != dp->d_devsw->d_maj) 4685603Sphk continue; 4785603Sphk u = dkunit(dev); 4885603Sphk p = RAW_PART; 4985603Sphk s = WHOLE_DISK_SLICE; 5085603Sphk pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p)); 5185603Sphk s = dkslice(dev); 5285603Sphk p = dkpart(dev); 5385603Sphk if (s == WHOLE_DISK_SLICE && p == RAW_PART) { 5485603Sphk /* XXX: actually should not happen */ 5585603Sphk dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 5685603Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%d", 5785603Sphk dp->d_devsw->d_name, u); 5885603Sphk dev_depends(pdev, dev); 5985603Sphk return; 6085603Sphk } 6185603Sphk if (s == COMPATIBILITY_SLICE) { 6285603Sphk dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 6385603Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%d%c", 6485603Sphk dp->d_devsw->d_name, u, 'a' + p); 6585603Sphk dev_depends(pdev, dev); 6685603Sphk return; 6785603Sphk } 6885603Sphk dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 6985603Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c", 7085603Sphk dp->d_devsw->d_name, u, s - BASE_SLICE + 1, 'a' + p); 7185603Sphk dev_depends(pdev, dev); 7285603Sphk if (p == RAW_PART) 7385603Sphk make_dev_alias(dev, "%s%ds%d", 7485603Sphk dp->d_devsw->d_name, u, s - BASE_SLICE + 1); 7585603Sphk return; 7685603Sphk } 7785603Sphk} 7885603Sphk 7962617Simpstatic void 8064880Sphkdisk_clone(void *arg, char *name, int namelen, dev_t *dev) 8164880Sphk{ 8264880Sphk struct disk *dp; 8364880Sphk char const *d; 8464880Sphk int i, u, s, p; 8564880Sphk dev_t pdev; 8664880Sphk 8764880Sphk if (*dev != NODEV) 8864880Sphk return; 8964880Sphk 9064880Sphk LIST_FOREACH(dp, &disklist, d_list) { 9164880Sphk d = dp->d_devsw->d_name; 9264880Sphk i = strlen(d); 9364880Sphk if (bcmp(d, name, i) != 0) 9464880Sphk continue; 9564880Sphk u = 0; 9664880Sphk if (!isdigit(name[i])) 9764880Sphk continue; 9864880Sphk while (isdigit(name[i])) { 9964880Sphk u *= 10; 10064880Sphk u += name[i++] - '0'; 10164880Sphk } 10270058Sphk if (u > DKMAXUNIT) 10370058Sphk continue; 10464880Sphk p = RAW_PART; 10564880Sphk s = WHOLE_DISK_SLICE; 10664880Sphk pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p)); 10764880Sphk if (pdev->si_disk == NULL) 10864880Sphk continue; 10964880Sphk if (name[i] != '\0') { 11064880Sphk if (name[i] == 's') { 11164880Sphk s = 0; 11264880Sphk i++; 11364880Sphk if (!isdigit(name[i])) 11464880Sphk continue; 11564880Sphk while (isdigit(name[i])) { 11664880Sphk s *= 10; 11764880Sphk s += name[i++] - '0'; 11864880Sphk } 11964880Sphk s += BASE_SLICE - 1; 12064880Sphk } else { 12164880Sphk s = COMPATIBILITY_SLICE; 12264880Sphk } 12364880Sphk if (name[i] == '\0') 12464880Sphk ; 12585311Sphk else if (name[i + 1] != '\0') 12685311Sphk return; 12764880Sphk else if (name[i] < 'a' || name[i] > 'h') 12864880Sphk continue; 12964880Sphk else 13064880Sphk p = name[i] - 'a'; 13164880Sphk } 13264880Sphk 13385603Sphk if (s >= BASE_SLICE) 13485603Sphk *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 13585603Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c", 13685603Sphk pdev->si_devsw->d_name, u, s - BASE_SLICE + 1, p + 'a'); 13785603Sphk else 13885603Sphk *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 13985603Sphk UID_ROOT, GID_OPERATOR, 0640, name); 14077215Sphk dev_depends(pdev, *dev); 14185603Sphk if (s >= BASE_SLICE && p == RAW_PART) { 14285603Sphk make_dev_alias(*dev, "%s%ds%d", 14385603Sphk pdev->si_devsw->d_name, u, s - BASE_SLICE + 1); 14485603Sphk } 14564880Sphk return; 14664880Sphk } 14764880Sphk} 14864880Sphk 14964880Sphkstatic void 15062617Simpinherit_raw(dev_t pdev, dev_t dev) 15162617Simp{ 15262617Simp dev->si_disk = pdev->si_disk; 15362617Simp dev->si_drv1 = pdev->si_drv1; 15462617Simp dev->si_drv2 = pdev->si_drv2; 15562617Simp dev->si_iosize_max = pdev->si_iosize_max; 15662617Simp dev->si_bsize_phys = pdev->si_bsize_phys; 15762617Simp dev->si_bsize_best = pdev->si_bsize_best; 15862617Simp} 15962617Simp 16050565Sphkdev_t 16151215Sphkdisk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto) 16250565Sphk{ 16364880Sphk static int once; 16477408Sphk dev_t dev; 16550565Sphk 16677215Sphk if (!once) { 16777215Sphk EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000); 16877215Sphk once++; 16977215Sphk } 17077215Sphk 17151198Sphk bzero(dp, sizeof(*dp)); 17251198Sphk 17377147Sphk if (proto->d_open != diskopen) { 17451215Sphk *proto = *cdevsw; 17551215Sphk proto->d_open = diskopen; 17651215Sphk proto->d_close = diskclose; 17751215Sphk proto->d_ioctl = diskioctl; 17851215Sphk proto->d_strategy = diskstrategy; 17951215Sphk proto->d_psize = diskpsize; 18077343Sphk cdevsw_add(proto); 18150565Sphk } 18250565Sphk 18353437Sjkh if (bootverbose) 18453437Sjkh printf("Creating DISK %s%d\n", cdevsw->d_name, unit); 18551243Sphk dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART), 18664880Sphk UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit); 18750565Sphk 18850565Sphk dev->si_disk = dp; 18950565Sphk dp->d_dev = dev; 19052917Sphk dp->d_dsflags = flags; 19151215Sphk dp->d_devsw = cdevsw; 19261717Sphk LIST_INSERT_HEAD(&disklist, dp, d_list); 19377215Sphk 19450565Sphk return (dev); 19550565Sphk} 19650565Sphk 19750728Sphkint 19850728Sphkdisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize) 19950728Sphk{ 20050728Sphk struct disk *dp; 20150728Sphk struct disklabel *dl; 20250728Sphk u_int boff; 20350728Sphk 20450728Sphk dp = dev->si_disk; 20550728Sphk if (!dp) 20650728Sphk return (ENXIO); 20750728Sphk if (!dp->d_slice) 20850728Sphk return (ENXIO); 20950728Sphk dl = dsgetlabel(dev, dp->d_slice); 21050728Sphk if (!dl) 21150728Sphk return (ENXIO); 21281688Sbde *count = Maxmem * (PAGE_SIZE / dl->d_secsize); 21381688Sbde if (dumplo <= LABELSECTOR || 21450728Sphk (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size)) 21550728Sphk return (EINVAL); 21650728Sphk boff = dl->d_partitions[dkpart(dev)].p_offset + 21750728Sphk dp->d_slice->dss_slices[dkslice(dev)].ds_offset; 21850728Sphk *blkno = boff + dumplo; 21950728Sphk *secsize = dl->d_secsize; 22050728Sphk return (0); 22150728Sphk 22250728Sphk} 22350728Sphk 22450728Sphkvoid 22550728Sphkdisk_invalidate (struct disk *disk) 22650728Sphk{ 22757325Ssos if (disk->d_slice) 22857325Ssos dsgone(&disk->d_slice); 22950728Sphk} 23050728Sphk 23150565Sphkvoid 23256767Sphkdisk_destroy(dev_t dev) 23350565Sphk{ 23461717Sphk LIST_REMOVE(dev->si_disk, d_list); 23561717Sphk bzero(dev->si_disk, sizeof(*dev->si_disk)); 23657325Ssos dev->si_disk = NULL; 23757325Ssos destroy_dev(dev); 23850565Sphk return; 23950565Sphk} 24050565Sphk 24161717Sphkstruct disk * 24261717Sphkdisk_enumerate(struct disk *disk) 24361717Sphk{ 24461717Sphk if (!disk) 24561717Sphk return (LIST_FIRST(&disklist)); 24661717Sphk else 24761717Sphk return (LIST_NEXT(disk, d_list)); 24861717Sphk} 24961717Sphk 25061953Snbmstatic int 25162573Sphksysctl_disks(SYSCTL_HANDLER_ARGS) 25261953Snbm{ 25361953Snbm struct disk *disk; 25461953Snbm int error, first; 25561953Snbm 25661953Snbm disk = NULL; 25761953Snbm first = 1; 25861953Snbm 25961953Snbm while ((disk = disk_enumerate(disk))) { 26061953Snbm if (!first) { 26161953Snbm error = SYSCTL_OUT(req, " ", 1); 26261953Snbm if (error) 26361953Snbm return error; 26461953Snbm } else { 26561953Snbm first = 0; 26661953Snbm } 26761953Snbm error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name)); 26861953Snbm if (error) 26961953Snbm return error; 27061953Snbm } 27161953Snbm error = SYSCTL_OUT(req, "", 1); 27261953Snbm return error; 27361953Snbm} 27461953Snbm 27561953SnbmSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL, 27661953Snbm sysctl_disks, "A", "names of available disks"); 27761953Snbm 27850728Sphk/* 27950728Sphk * The cdevsw functions 28050728Sphk */ 28150728Sphk 28250565Sphkstatic int 28383366Sjuliandiskopen(dev_t dev, int oflags, int devtype, struct thread *td) 28450565Sphk{ 28550565Sphk dev_t pdev; 28650565Sphk struct disk *dp; 28750565Sphk int error; 28850565Sphk 28950728Sphk error = 0; 29050565Sphk pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 29150728Sphk 29250565Sphk dp = pdev->si_disk; 29350565Sphk if (!dp) 29450565Sphk return (ENXIO); 29550728Sphk 29652917Sphk while (dp->d_flags & DISKFLAG_LOCK) { 29752917Sphk dp->d_flags |= DISKFLAG_WANTED; 29854815Sphk error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz); 29954815Sphk if (error) 30054815Sphk return (error); 30152917Sphk } 30252917Sphk dp->d_flags |= DISKFLAG_LOCK; 30352917Sphk 30451860Sphk if (!dsisopen(dp->d_slice)) { 30551878Ssos if (!pdev->si_iosize_max) 30651878Ssos pdev->si_iosize_max = dev->si_iosize_max; 30783366Sjulian error = dp->d_devsw->d_open(pdev, oflags, devtype, td); 30851860Sphk } 30951826Sphk 31051826Sphk /* Inherit properties from the whole/raw dev_t */ 31162617Simp inherit_raw(pdev, dev); 31250728Sphk 31350728Sphk if (error) 31452917Sphk goto out; 31550728Sphk 31652917Sphk error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label); 31750565Sphk 31850728Sphk if (!dsisopen(dp->d_slice)) 31983366Sjulian dp->d_devsw->d_close(pdev, oflags, devtype, td); 32052917Sphkout: 32152917Sphk dp->d_flags &= ~DISKFLAG_LOCK; 32252917Sphk if (dp->d_flags & DISKFLAG_WANTED) { 32352917Sphk dp->d_flags &= ~DISKFLAG_WANTED; 32452917Sphk wakeup(dp); 32552917Sphk } 32650728Sphk 32750565Sphk return(error); 32850565Sphk} 32950565Sphk 33050565Sphkstatic int 33183366Sjuliandiskclose(dev_t dev, int fflag, int devtype, struct thread *td) 33250565Sphk{ 33350565Sphk struct disk *dp; 33450565Sphk int error; 33562617Simp dev_t pdev; 33650565Sphk 33750565Sphk error = 0; 33862617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 33962617Simp dp = pdev->si_disk; 34074206Ssos if (!dp) 34174206Ssos return (ENXIO); 34251822Sphk dsclose(dev, devtype, dp->d_slice); 34374206Ssos if (!dsisopen(dp->d_slice)) 34483366Sjulian error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, td); 34550565Sphk return (error); 34650565Sphk} 34750565Sphk 34850565Sphkstatic void 34959249Sphkdiskstrategy(struct bio *bp) 35050565Sphk{ 35150565Sphk dev_t pdev; 35250565Sphk struct disk *dp; 35350565Sphk 35462617Simp pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART); 35562617Simp dp = pdev->si_disk; 35676361Sphk bp->bio_resid = bp->bio_bcount; 35762617Simp if (dp != bp->bio_dev->si_disk) 35862617Simp inherit_raw(pdev, bp->bio_dev); 35950565Sphk 36050565Sphk if (!dp) { 36176322Sphk biofinish(bp, NULL, ENXIO); 36250565Sphk return; 36350565Sphk } 36450565Sphk 36555763Sphk if (dscheck(bp, dp->d_slice) <= 0) { 36650565Sphk biodone(bp); 36750565Sphk return; 36850565Sphk } 36950565Sphk 37076324Sphk if (bp->bio_bcount == 0) { 37176324Sphk biodone(bp); 37276324Sphk return; 37376324Sphk } 37476324Sphk 37559623Sphk KASSERT(dp->d_devsw != NULL, ("NULL devsw")); 37659623Sphk KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy")); 37751215Sphk dp->d_devsw->d_strategy(bp); 37850565Sphk return; 37950565Sphk 38050565Sphk} 38150565Sphk 38250565Sphkstatic int 38383366Sjuliandiskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 38450565Sphk{ 38550565Sphk struct disk *dp; 38650565Sphk int error; 38762617Simp dev_t pdev; 38850565Sphk 38962617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 39062617Simp dp = pdev->si_disk; 39174206Ssos if (!dp) 39274206Ssos return (ENXIO); 39350565Sphk error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 39450565Sphk if (error == ENOIOCTL) 39583366Sjulian error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, td); 39650565Sphk return (error); 39750565Sphk} 39850565Sphk 39950565Sphkstatic int 40050565Sphkdiskpsize(dev_t dev) 40150565Sphk{ 40250565Sphk struct disk *dp; 40350728Sphk dev_t pdev; 40450565Sphk 40562617Simp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 40662617Simp dp = pdev->si_disk; 40762617Simp if (!dp) 40862617Simp return (-1); 40962617Simp if (dp != dev->si_disk) { 41050728Sphk dev->si_drv1 = pdev->si_drv1; 41150728Sphk dev->si_drv2 = pdev->si_drv2; 41250728Sphk /* XXX: don't set bp->b_dev->si_disk (?) */ 41350728Sphk } 41450565Sphk return (dssize(dev, &dp->d_slice)); 41550565Sphk} 41651111Sjulian 41751111SjulianSYSCTL_DECL(_debug_sizeof); 41851111Sjulian 41951111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 42051111Sjulian 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 42151111Sjulian 42251111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 42351111Sjulian 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 42451111Sjulian 42551111SjulianSYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 42651111Sjulian 0, sizeof(struct disk), "sizeof(struct disk)"); 427