subr_disk.c revision 76324
142421Syokota/* 242421Syokota * ---------------------------------------------------------------------------- 342421Syokota * "THE BEER-WARE LICENSE" (Revision 42): 442421Syokota * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 542421Syokota * can do whatever you want with this stuff. If we meet some day, and you think 642421Syokota * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 742421Syokota * ---------------------------------------------------------------------------- 842421Syokota * 942421Syokota * $FreeBSD: head/sys/kern/subr_disk.c 76324 2001-05-06 21:55:22Z phk $ 1042421Syokota * 1142421Syokota */ 1242421Syokota 1342421Syokota#include <sys/param.h> 1442421Syokota#include <sys/systm.h> 1542421Syokota#include <sys/kernel.h> 1642421Syokota#include <sys/sysctl.h> 1742421Syokota#include <sys/bio.h> 1842421Syokota#include <sys/conf.h> 1942421Syokota#include <sys/disk.h> 2042421Syokota#include <sys/malloc.h> 2142421Syokota#include <sys/sysctl.h> 2242421Syokota#include <machine/md_var.h> 2342421Syokota#include <sys/ctype.h> 2442421Syokota 2542421Syokotastatic MALLOC_DEFINE(M_DISK, "disk", "disk data"); 2642421Syokota 2742421Syokotastatic d_strategy_t diskstrategy; 28119418Sobrienstatic d_open_t diskopen; 29119418Sobrienstatic d_close_t diskclose; 30119418Sobrienstatic d_ioctl_t diskioctl; 3142421Syokotastatic d_psize_t diskpsize; 3242421Syokota 3342421Syokotastatic LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist); 3442421Syokota 3542421Syokotastatic void 3642421Syokotadisk_clone(void *arg, char *name, int namelen, dev_t *dev) 3742421Syokota{ 38139193Sphk struct disk *dp; 3942421Syokota char const *d; 4042421Syokota int i, u, s, p; 41112050Sdwmalone dev_t pdev; 42112050Sdwmalone 4342421Syokota if (*dev != NODEV) 4442421Syokota return; 4566834Sphk 4642421Syokota LIST_FOREACH(dp, &disklist, d_list) { 4742421Syokota d = dp->d_devsw->d_name; 4842421Syokota i = strlen(d); 4950154Syokota if (bcmp(d, name, i) != 0) 5050154Syokota continue; 5150154Syokota u = 0; 5250154Syokota if (!isdigit(name[i])) 5350154Syokota continue; 5450154Syokota while (isdigit(name[i])) { 5550154Syokota u *= 10; 5650154Syokota u += name[i++] - '0'; 5750154Syokota } 5860938Sjake if (u > DKMAXUNIT) 59127751Sdes continue; 6054545Syokota p = RAW_PART; 6178161Speter s = WHOLE_DISK_SLICE; 6278161Speter pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p)); 6342421Syokota if (pdev->si_disk == NULL) 6442421Syokota continue; 6542421Syokota if (name[i] != '\0') { 6642421Syokota if (name[i] == 's') { 6742421Syokota s = 0; 6842421Syokota i++; 6942421Syokota if (!isdigit(name[i])) 7042564Syokota continue; 7142564Syokota while (isdigit(name[i])) { 7242421Syokota s *= 10; 7342564Syokota s += name[i++] - '0'; 7442421Syokota } 7542421Syokota s += BASE_SLICE - 1; 7642421Syokota } else { 77112050Sdwmalone s = COMPATIBILITY_SLICE; 78112050Sdwmalone } 79112050Sdwmalone if (name[i] == '\0') 80112050Sdwmalone ; 81112050Sdwmalone else if (name[i] < 'a' || name[i] > 'h') 8242421Syokota continue; 8342421Syokota else 8444628Syokota p = name[i] - 'a'; 8542421Syokota } 8642421Syokota 8742421Syokota *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 8842421Syokota UID_ROOT, GID_OPERATOR, 0640, name); 8942421Syokota return; 9042421Syokota } 9142421Syokota} 9242421Syokota 9342421Syokotastatic void 9469781Sdwmaloneinherit_raw(dev_t pdev, dev_t dev) 9544628Syokota{ 9644628Syokota dev->si_disk = pdev->si_disk; 97127752Sdes dev->si_drv1 = pdev->si_drv1; 9844628Syokota dev->si_drv2 = pdev->si_drv2; 9969781Sdwmalone dev->si_iosize_max = pdev->si_iosize_max; 10069781Sdwmalone dev->si_bsize_phys = pdev->si_bsize_phys; 10144628Syokota dev->si_bsize_best = pdev->si_bsize_best; 10244628Syokota} 10344628Syokota 104127752Sdesdev_t 10544628Syokotadisk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto) 10642421Syokota{ 10742421Syokota static int once; 10842421Syokota dev_t dev; 10942421Syokota 11042421Syokota bzero(dp, sizeof(*dp)); 11142421Syokota 11242421Syokota dev = makedev(cdevsw->d_maj, 0); 11342421Syokota if (!devsw(dev)) { 11442421Syokota *proto = *cdevsw; 11542421Syokota proto->d_open = diskopen; 11642421Syokota proto->d_close = diskclose; 11742421Syokota proto->d_ioctl = diskioctl; 11842421Syokota proto->d_strategy = diskstrategy; 11944628Syokota proto->d_psize = diskpsize; 120127752Sdes cdevsw_add(proto); 12142421Syokota } 12242421Syokota 12342421Syokota if (bootverbose) 12442421Syokota printf("Creating DISK %s%d\n", cdevsw->d_name, unit); 12542421Syokota dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART), 12642421Syokota UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit); 12742421Syokota 12842421Syokota dev->si_disk = dp; 12942421Syokota dp->d_dev = dev; 13042421Syokota dp->d_dsflags = flags; 13142421Syokota dp->d_devsw = cdevsw; 13242421Syokota LIST_INSERT_HEAD(&disklist, dp, d_list); 13342421Syokota if (!once) { 13442421Syokota EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000); 13542421Syokota once++; 13642421Syokota } 13742421Syokota return (dev); 13842421Syokota} 13944628Syokota 14042421Syokotaint 14142421Syokotadisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize) 14242421Syokota{ 14342421Syokota struct disk *dp; 14442421Syokota struct disklabel *dl; 14542421Syokota u_int boff; 14642421Syokota 14742421Syokota dp = dev->si_disk; 14844628Syokota if (!dp) 14944628Syokota return (ENXIO); 15054382Syokota if (!dp->d_slice) 15180040Syokota return (ENXIO); 15242421Syokota dl = dsgetlabel(dev, dp->d_slice); 15342421Syokota if (!dl) 15442421Syokota return (ENXIO); 15542421Syokota *count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize; 15642421Syokota if (dumplo < 0 || 15742421Syokota (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size)) 15842421Syokota return (EINVAL); 15942421Syokota boff = dl->d_partitions[dkpart(dev)].p_offset + 16042421Syokota dp->d_slice->dss_slices[dkslice(dev)].ds_offset; 16142421Syokota *blkno = boff + dumplo; 16242421Syokota *secsize = dl->d_secsize; 16342421Syokota return (0); 16454545Syokota 16554545Syokota} 16654545Syokota 16754545Syokotavoid 16854545Syokotadisk_invalidate (struct disk *disk) 169127752Sdes{ 17054545Syokota if (disk->d_slice) 171127752Sdes dsgone(&disk->d_slice); 17254545Syokota} 17354545Syokota 17454545Syokotavoid 17554545Syokotadisk_destroy(dev_t dev) 17654545Syokota{ 17760938Sjake LIST_REMOVE(dev->si_disk, d_list); 17854545Syokota bzero(dev->si_disk, sizeof(*dev->si_disk)); 179127752Sdes dev->si_disk = NULL; 18054545Syokota destroy_dev(dev); 18154545Syokota return; 18242421Syokota} 18342421Syokota 18442421Syokotastruct disk * 18542421Syokotadisk_enumerate(struct disk *disk) 18647295Syokota{ 18747295Syokota if (!disk) 188156126Semax return (LIST_FIRST(&disklist)); 189156126Semax else 19042421Syokota return (LIST_NEXT(disk, d_list)); 19142421Syokota} 192156126Semax 193156126Semaxstatic int 19442421Syokotasysctl_disks(SYSCTL_HANDLER_ARGS) 19542421Syokota{ 19642421Syokota struct disk *disk; 19742421Syokota int error, first; 19844628Syokota 19944628Syokota disk = NULL; 200127752Sdes first = 1; 20144628Syokota 20242421Syokota while ((disk = disk_enumerate(disk))) { 20342421Syokota if (!first) { 20442421Syokota error = SYSCTL_OUT(req, " ", 1); 20542421Syokota if (error) 20642421Syokota return error; 20742421Syokota } else { 20842421Syokota first = 0; 20942421Syokota } 21042421Syokota error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name)); 21154545Syokota if (error) 21254545Syokota return error; 21354545Syokota } 21454545Syokota error = SYSCTL_OUT(req, "", 1); 215156126Semax return error; 216156126Semax} 217156126Semax 218156126SemaxSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL, 219156126Semax sysctl_disks, "A", "names of available disks"); 220156126Semax 221156126Semax/* 222156126Semax * The cdevsw functions 223156126Semax */ 224156126Semax 225127752Sdesstatic int 22654545Syokotadiskopen(dev_t dev, int oflags, int devtype, struct proc *p) 22754545Syokota{ 22878161Speter dev_t pdev; 22978161Speter struct disk *dp; 23042421Syokota int error; 23142421Syokota 23242421Syokota error = 0; 233156126Semax pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 234156126Semax 235156126Semax dp = pdev->si_disk; 236156126Semax if (!dp) 237156126Semax return (ENXIO); 238156126Semax 239156126Semax while (dp->d_flags & DISKFLAG_LOCK) { 240156126Semax dp->d_flags |= DISKFLAG_WANTED; 241156126Semax error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz); 242156126Semax if (error) 243127752Sdes return (error); 24442421Syokota } 24542421Syokota dp->d_flags |= DISKFLAG_LOCK; 24642421Syokota 247127752Sdes if (!dsisopen(dp->d_slice)) { 24842421Syokota if (!pdev->si_iosize_max) 24942421Syokota pdev->si_iosize_max = dev->si_iosize_max; 25042421Syokota error = dp->d_devsw->d_open(pdev, oflags, devtype, p); 25142421Syokota } 25242421Syokota 25342421Syokota /* Inherit properties from the whole/raw dev_t */ 25442421Syokota inherit_raw(pdev, dev); 25542421Syokota 25642421Syokota if (error) 257127752Sdes goto out; 25842421Syokota 259127752Sdes error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label); 26042421Syokota 26142421Syokota if (!dsisopen(dp->d_slice)) 26242421Syokota dp->d_devsw->d_close(pdev, oflags, devtype, p); 26342421Syokotaout: 264127752Sdes dp->d_flags &= ~DISKFLAG_LOCK; 26542421Syokota if (dp->d_flags & DISKFLAG_WANTED) { 26642421Syokota dp->d_flags &= ~DISKFLAG_WANTED; 267127752Sdes wakeup(dp); 26842421Syokota } 26942421Syokota 27042421Syokota return(error); 271127752Sdes} 27242421Syokota 27342421Syokotastatic int 27442421Syokotadiskclose(dev_t dev, int fflag, int devtype, struct proc *p) 27542421Syokota{ 27642421Syokota struct disk *dp; 27742421Syokota int error; 27842421Syokota dev_t pdev; 279127752Sdes 28042421Syokota error = 0; 28142421Syokota pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 28242421Syokota dp = pdev->si_disk; 28342421Syokota if (!dp) 28442421Syokota return (ENXIO); 28542421Syokota dsclose(dev, devtype, dp->d_slice); 28647295Syokota if (!dsisopen(dp->d_slice)) 28747295Syokota error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p); 28842421Syokota return (error); 28954545Syokota} 29054545Syokota 291127752Sdesstatic void 29254545Syokotadiskstrategy(struct bio *bp) 29378161Speter{ 29478161Speter dev_t pdev; 29542421Syokota struct disk *dp; 296127752Sdes 29742421Syokota pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART); 29842421Syokota dp = pdev->si_disk; 299127752Sdes if (dp != bp->bio_dev->si_disk) 30042421Syokota inherit_raw(pdev, bp->bio_dev); 30142421Syokota 30242421Syokota if (!dp) { 30342421Syokota biofinish(bp, NULL, ENXIO); 30442421Syokota return; 30542421Syokota } 30642421Syokota 30742421Syokota if (dscheck(bp, dp->d_slice) <= 0) { 30842421Syokota biodone(bp); 309147980Semax return; 310147980Semax } 311147980Semax 312147980Semax if (bp->bio_bcount == 0) { 31342421Syokota bp->bio_resid = 0; 314147980Semax biodone(bp); 31542421Syokota return; 31642421Syokota } 31742421Syokota 318147980Semax KASSERT(dp->d_devsw != NULL, ("NULL devsw")); 319147980Semax KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy")); 320147980Semax dp->d_devsw->d_strategy(bp); 321147980Semax return; 32242421Syokota 32342421Syokota} 32442421Syokota 32542421Syokotastatic int 32642421Syokotadiskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) 32742421Syokota{ 32842421Syokota struct disk *dp; 32942421Syokota int error; 330127752Sdes dev_t pdev; 33142421Syokota 332147980Semax pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 333127752Sdes dp = pdev->si_disk; 33442421Syokota if (!dp) 33542421Syokota return (ENXIO); 336147980Semax error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 337147980Semax if (error == ENOIOCTL) 338147980Semax error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p); 339147980Semax return (error); 340147980Semax} 341147980Semax 342147980Semaxstatic int 34342421Syokotadiskpsize(dev_t dev) 34442421Syokota{ 34542421Syokota struct disk *dp; 34642421Syokota dev_t pdev; 34742421Syokota 34842421Syokota pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 34942421Syokota dp = pdev->si_disk; 35042421Syokota if (!dp) 35142421Syokota return (-1); 352127752Sdes if (dp != dev->si_disk) { 35342421Syokota dev->si_drv1 = pdev->si_drv1; 35442421Syokota dev->si_drv2 = pdev->si_drv2; 35542421Syokota /* XXX: don't set bp->b_dev->si_disk (?) */ 35642421Syokota } 35742421Syokota return (dssize(dev, &dp->d_slice)); 35842421Syokota} 359127752Sdes 36042421SyokotaSYSCTL_DECL(_debug_sizeof); 36142421Syokota 36242421SyokotaSYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 36342421Syokota 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 36442421Syokota 36542421SyokotaSYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 36642421Syokota 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 36742421Syokota 368127752SdesSYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 36942421Syokota 0, sizeof(struct disk), "sizeof(struct disk)"); 37042421Syokota