subr_disk.c revision 62617
133965Sjdp/* 289857Sobrien * ---------------------------------------------------------------------------- 389857Sobrien * "THE BEER-WARE LICENSE" (Revision 42): 433965Sjdp * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 533965Sjdp * can do whatever you want with this stuff. If we meet some day, and you think 633965Sjdp * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 733965Sjdp * ---------------------------------------------------------------------------- 833965Sjdp * 933965Sjdp * $FreeBSD: head/sys/kern/subr_disk.c 62617 2000-07-05 06:01:33Z imp $ 1033965Sjdp * 1133965Sjdp */ 1233965Sjdp 1333965Sjdp#include <sys/param.h> 1433965Sjdp#include <sys/systm.h> 1533965Sjdp#include <sys/kernel.h> 1633965Sjdp#include <sys/sysctl.h> 1733965Sjdp#include <sys/bio.h> 1833965Sjdp#include <sys/conf.h> 1933965Sjdp#include <sys/disk.h> 2033965Sjdp#include <sys/malloc.h> 2133965Sjdp#include <sys/sysctl.h> 2233965Sjdp#include <machine/md_var.h> 2333965Sjdp 2433965SjdpMALLOC_DEFINE(M_DISK, "disk", "disk data"); 2533965Sjdp 2633965Sjdpstatic d_strategy_t diskstrategy; 2733965Sjdpstatic d_open_t diskopen; 2833965Sjdpstatic d_close_t diskclose; 2933965Sjdpstatic d_ioctl_t diskioctl; 3033965Sjdpstatic d_psize_t diskpsize; 3133965Sjdp 3233965Sjdpstatic LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist); 3389857Sobrien 3489857Sobrienstatic void 3589857Sobrieninherit_raw(dev_t pdev, dev_t dev) 3689857Sobrien{ 3789857Sobrien dev->si_disk = pdev->si_disk; 3889857Sobrien dev->si_drv1 = pdev->si_drv1; 3989857Sobrien dev->si_drv2 = pdev->si_drv2; 4033965Sjdp dev->si_iosize_max = pdev->si_iosize_max; 4133965Sjdp dev->si_bsize_phys = pdev->si_bsize_phys; 4233965Sjdp dev->si_bsize_best = pdev->si_bsize_best; 4389857Sobrien} 4433965Sjdp 4533965Sjdpdev_t 4633965Sjdpdisk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto) 4733965Sjdp{ 4833965Sjdp dev_t dev; 4933965Sjdp 5033965Sjdp bzero(dp, sizeof(*dp)); 5133965Sjdp 5233965Sjdp dev = makedev(cdevsw->d_maj, 0); 5333965Sjdp if (!devsw(dev)) { 5433965Sjdp *proto = *cdevsw; 5533965Sjdp proto->d_open = diskopen; 5689857Sobrien proto->d_close = diskclose; 5733965Sjdp proto->d_ioctl = diskioctl; 5833965Sjdp proto->d_strategy = diskstrategy; 5933965Sjdp proto->d_psize = diskpsize; 6033965Sjdp cdevsw_add(proto); 6133965Sjdp } 6233965Sjdp 6333965Sjdp if (bootverbose) 6433965Sjdp printf("Creating DISK %s%d\n", cdevsw->d_name, unit); 6533965Sjdp dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART), 6633965Sjdp 0, 0, 0, "%s%d", cdevsw->d_name, unit); 6733965Sjdp 6833965Sjdp dev->si_disk = dp; 6933965Sjdp dp->d_dev = dev; 7033965Sjdp dp->d_dsflags = flags; 7133965Sjdp dp->d_devsw = cdevsw; 7233965Sjdp LIST_INSERT_HEAD(&disklist, dp, d_list); 7333965Sjdp return (dev); 7433965Sjdp} 7533965Sjdp 7633965Sjdpint 7733965Sjdpdisk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize) 7833965Sjdp{ 7933965Sjdp struct disk *dp; 8033965Sjdp struct disklabel *dl; 8133965Sjdp u_int boff; 8233965Sjdp 8333965Sjdp dp = dev->si_disk; 8433965Sjdp if (!dp) 8589857Sobrien return (ENXIO); 8633965Sjdp if (!dp->d_slice) 8789857Sobrien return (ENXIO); 8889857Sobrien dl = dsgetlabel(dev, dp->d_slice); 8933965Sjdp if (!dl) 9033965Sjdp return (ENXIO); 9133965Sjdp *count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize; 9233965Sjdp if (dumplo < 0 || 9333965Sjdp (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size)) 9433965Sjdp return (EINVAL); 9533965Sjdp boff = dl->d_partitions[dkpart(dev)].p_offset + 9689857Sobrien dp->d_slice->dss_slices[dkslice(dev)].ds_offset; 9733965Sjdp *blkno = boff + dumplo; 9833965Sjdp *secsize = dl->d_secsize; 9933965Sjdp return (0); 10033965Sjdp 10133965Sjdp} 10233965Sjdp 10333965Sjdpvoid 10433965Sjdpdisk_invalidate (struct disk *disk) 10533965Sjdp{ 10633965Sjdp if (disk->d_slice) 10733965Sjdp dsgone(&disk->d_slice); 10889857Sobrien} 10989857Sobrien 11033965Sjdpvoid 11133965Sjdpdisk_destroy(dev_t dev) 11233965Sjdp{ 11333965Sjdp LIST_REMOVE(dev->si_disk, d_list); 11433965Sjdp bzero(dev->si_disk, sizeof(*dev->si_disk)); 11533965Sjdp dev->si_disk = NULL; 11633965Sjdp destroy_dev(dev); 11733965Sjdp return; 11833965Sjdp} 11933965Sjdp 12033965Sjdpstruct disk * 12133965Sjdpdisk_enumerate(struct disk *disk) 12233965Sjdp{ 12333965Sjdp if (!disk) 12433965Sjdp return (LIST_FIRST(&disklist)); 12533965Sjdp else 12633965Sjdp return (LIST_NEXT(disk, d_list)); 12733965Sjdp} 12833965Sjdp 12933965Sjdpstatic int 13033965Sjdpsysctl_disks(SYSCTL_HANDLER_ARGS) 13133965Sjdp{ 13260484Sobrien struct disk *disk; 13333965Sjdp int error, first; 13433965Sjdp 13533965Sjdp disk = NULL; 13633965Sjdp first = 1; 13733965Sjdp 13833965Sjdp while ((disk = disk_enumerate(disk))) { 13933965Sjdp if (!first) { 14033965Sjdp error = SYSCTL_OUT(req, " ", 1); 14189857Sobrien if (error) 14233965Sjdp return error; 14333965Sjdp } else { 14433965Sjdp first = 0; 14533965Sjdp } 14633965Sjdp error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name)); 14789857Sobrien if (error) 14889857Sobrien return error; 14989857Sobrien } 15089857Sobrien error = SYSCTL_OUT(req, "", 1); 15189857Sobrien return error; 15289857Sobrien} 15333965Sjdp 15433965SjdpSYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL, 15533965Sjdp sysctl_disks, "A", "names of available disks"); 15633965Sjdp 15733965Sjdp/* 15833965Sjdp * The cdevsw functions 15933965Sjdp */ 16033965Sjdp 16133965Sjdpstatic int 16233965Sjdpdiskopen(dev_t dev, int oflags, int devtype, struct proc *p) 16333965Sjdp{ 16433965Sjdp dev_t pdev; 16533965Sjdp struct disk *dp; 16633965Sjdp int error; 16733965Sjdp 16833965Sjdp error = 0; 16933965Sjdp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 17033965Sjdp 17133965Sjdp dp = pdev->si_disk; 17233965Sjdp if (!dp) 17389857Sobrien return (ENXIO); 17489857Sobrien 17533965Sjdp while (dp->d_flags & DISKFLAG_LOCK) { 17633965Sjdp dp->d_flags |= DISKFLAG_WANTED; 17733965Sjdp error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz); 17833965Sjdp if (error) 17933965Sjdp return (error); 18033965Sjdp } 18133965Sjdp dp->d_flags |= DISKFLAG_LOCK; 18233965Sjdp 18333965Sjdp if (!dsisopen(dp->d_slice)) { 18433965Sjdp if (!pdev->si_iosize_max) 18533965Sjdp pdev->si_iosize_max = dev->si_iosize_max; 18633965Sjdp error = dp->d_devsw->d_open(pdev, oflags, devtype, p); 18733965Sjdp } 18833965Sjdp 18933965Sjdp /* Inherit properties from the whole/raw dev_t */ 19033965Sjdp inherit_raw(pdev, dev); 19133965Sjdp 19233965Sjdp if (error) 19333965Sjdp goto out; 19433965Sjdp 19533965Sjdp error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label); 19633965Sjdp 19733965Sjdp if (!dsisopen(dp->d_slice)) 19833965Sjdp dp->d_devsw->d_close(pdev, oflags, devtype, p); 19933965Sjdpout: 20033965Sjdp dp->d_flags &= ~DISKFLAG_LOCK; 20133965Sjdp if (dp->d_flags & DISKFLAG_WANTED) { 20233965Sjdp dp->d_flags &= ~DISKFLAG_WANTED; 20333965Sjdp wakeup(dp); 20433965Sjdp } 20533965Sjdp 20633965Sjdp return(error); 20733965Sjdp} 20833965Sjdp 20933965Sjdpstatic int 21033965Sjdpdiskclose(dev_t dev, int fflag, int devtype, struct proc *p) 21133965Sjdp{ 21233965Sjdp struct disk *dp; 21333965Sjdp int error; 21433965Sjdp dev_t pdev; 21533965Sjdp 21633965Sjdp error = 0; 21733965Sjdp pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 21833965Sjdp dp = pdev->si_disk; 21933965Sjdp dsclose(dev, devtype, dp->d_slice); 22033965Sjdp if (!dsisopen(dp->d_slice)) { 22133965Sjdp error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p); 22233965Sjdp } 22333965Sjdp return (error); 22433965Sjdp} 22589857Sobrien 22689857Sobrienstatic void 22789857Sobriendiskstrategy(struct bio *bp) 22889857Sobrien{ 22989857Sobrien dev_t pdev; 23089857Sobrien struct disk *dp; 23189857Sobrien 23289857Sobrien pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART); 23389857Sobrien dp = pdev->si_disk; 23489857Sobrien if (dp != bp->bio_dev->si_disk) 23560484Sobrien inherit_raw(pdev, bp->bio_dev); 23689857Sobrien 23733965Sjdp if (!dp) { 23833965Sjdp bp->bio_error = ENXIO; 239 bp->bio_flags |= BIO_ERROR; 240 biodone(bp); 241 return; 242 } 243 244 if (dscheck(bp, dp->d_slice) <= 0) { 245 biodone(bp); 246 return; 247 } 248 249 KASSERT(dp->d_devsw != NULL, ("NULL devsw")); 250 KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy")); 251 dp->d_devsw->d_strategy(bp); 252 return; 253 254} 255 256static int 257diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) 258{ 259 struct disk *dp; 260 int error; 261 dev_t pdev; 262 263 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 264 dp = pdev->si_disk; 265 error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 266 if (error == ENOIOCTL) 267 error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p); 268 return (error); 269} 270 271static int 272diskpsize(dev_t dev) 273{ 274 struct disk *dp; 275 dev_t pdev; 276 277 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 278 dp = pdev->si_disk; 279 if (!dp) 280 return (-1); 281 if (dp != dev->si_disk) { 282 dev->si_drv1 = pdev->si_drv1; 283 dev->si_drv2 = pdev->si_drv2; 284 /* XXX: don't set bp->b_dev->si_disk (?) */ 285 } 286 return (dssize(dev, &dp->d_slice)); 287} 288 289SYSCTL_DECL(_debug_sizeof); 290 291SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 292 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 293 294SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 295 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 296 297SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 298 0, sizeof(struct disk), "sizeof(struct disk)"); 299