subr_disk.c revision 61953
1/* 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 5 * can do whatever you want with this stuff. If we meet some day, and you think 6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7 * ---------------------------------------------------------------------------- 8 * 9 * $FreeBSD: head/sys/kern/subr_disk.c 61953 2000-06-22 11:44:43Z nbm $ 10 * 11 */ 12 13#include <sys/param.h> 14#include <sys/systm.h> 15#include <sys/kernel.h> 16#include <sys/sysctl.h> 17#include <sys/bio.h> 18#include <sys/conf.h> 19#include <sys/disk.h> 20#include <sys/malloc.h> 21#include <sys/sysctl.h> 22#include <machine/md_var.h> 23 24MALLOC_DEFINE(M_DISK, "disk", "disk data"); 25 26static d_strategy_t diskstrategy; 27static d_open_t diskopen; 28static d_close_t diskclose; 29static d_ioctl_t diskioctl; 30static d_psize_t diskpsize; 31 32static LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist); 33 34dev_t 35disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto) 36{ 37 dev_t dev; 38 39 bzero(dp, sizeof(*dp)); 40 41 dev = makedev(cdevsw->d_maj, 0); 42 if (!devsw(dev)) { 43 *proto = *cdevsw; 44 proto->d_open = diskopen; 45 proto->d_close = diskclose; 46 proto->d_ioctl = diskioctl; 47 proto->d_strategy = diskstrategy; 48 proto->d_psize = diskpsize; 49 cdevsw_add(proto); 50 } 51 52 if (bootverbose) 53 printf("Creating DISK %s%d\n", cdevsw->d_name, unit); 54 dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART), 55 0, 0, 0, "%s%d", cdevsw->d_name, unit); 56 57 dev->si_disk = dp; 58 dp->d_dev = dev; 59 dp->d_dsflags = flags; 60 dp->d_devsw = cdevsw; 61 LIST_INSERT_HEAD(&disklist, dp, d_list); 62 return (dev); 63} 64 65int 66disk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize) 67{ 68 struct disk *dp; 69 struct disklabel *dl; 70 u_int boff; 71 72 dp = dev->si_disk; 73 if (!dp) 74 return (ENXIO); 75 if (!dp->d_slice) 76 return (ENXIO); 77 dl = dsgetlabel(dev, dp->d_slice); 78 if (!dl) 79 return (ENXIO); 80 *count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize; 81 if (dumplo < 0 || 82 (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size)) 83 return (EINVAL); 84 boff = dl->d_partitions[dkpart(dev)].p_offset + 85 dp->d_slice->dss_slices[dkslice(dev)].ds_offset; 86 *blkno = boff + dumplo; 87 *secsize = dl->d_secsize; 88 return (0); 89 90} 91 92void 93disk_invalidate (struct disk *disk) 94{ 95 if (disk->d_slice) 96 dsgone(&disk->d_slice); 97} 98 99void 100disk_destroy(dev_t dev) 101{ 102 LIST_REMOVE(dev->si_disk, d_list); 103 bzero(dev->si_disk, sizeof(*dev->si_disk)); 104 dev->si_disk = NULL; 105 destroy_dev(dev); 106 return; 107} 108 109struct disk * 110disk_enumerate(struct disk *disk) 111{ 112 if (!disk) 113 return (LIST_FIRST(&disklist)); 114 else 115 return (LIST_NEXT(disk, d_list)); 116} 117 118static int 119sysctl_disks SYSCTL_HANDLER_ARGS 120{ 121 struct disk *disk; 122 int error, first; 123 124 disk = NULL; 125 first = 1; 126 127 while ((disk = disk_enumerate(disk))) { 128 if (!first) { 129 error = SYSCTL_OUT(req, " ", 1); 130 if (error) 131 return error; 132 } else { 133 first = 0; 134 } 135 error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name)); 136 if (error) 137 return error; 138 } 139 error = SYSCTL_OUT(req, "", 1); 140 return error; 141} 142 143SYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL, 144 sysctl_disks, "A", "names of available disks"); 145 146/* 147 * The cdevsw functions 148 */ 149 150static int 151diskopen(dev_t dev, int oflags, int devtype, struct proc *p) 152{ 153 dev_t pdev; 154 struct disk *dp; 155 int error; 156 157 error = 0; 158 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 159 160 dp = pdev->si_disk; 161 if (!dp) 162 return (ENXIO); 163 164 while (dp->d_flags & DISKFLAG_LOCK) { 165 dp->d_flags |= DISKFLAG_WANTED; 166 error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz); 167 if (error) 168 return (error); 169 } 170 dp->d_flags |= DISKFLAG_LOCK; 171 172 if (!dsisopen(dp->d_slice)) { 173 if (!pdev->si_iosize_max) 174 pdev->si_iosize_max = dev->si_iosize_max; 175 error = dp->d_devsw->d_open(pdev, oflags, devtype, p); 176 } 177 178 /* Inherit properties from the whole/raw dev_t */ 179 dev->si_disk = pdev->si_disk; 180 dev->si_drv1 = pdev->si_drv1; 181 dev->si_drv2 = pdev->si_drv2; 182 dev->si_iosize_max = pdev->si_iosize_max; 183 dev->si_bsize_phys = pdev->si_bsize_phys; 184 dev->si_bsize_best = pdev->si_bsize_best; 185 186 if (error) 187 goto out; 188 189 error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label); 190 191 if (!dsisopen(dp->d_slice)) 192 dp->d_devsw->d_close(pdev, oflags, devtype, p); 193out: 194 dp->d_flags &= ~DISKFLAG_LOCK; 195 if (dp->d_flags & DISKFLAG_WANTED) { 196 dp->d_flags &= ~DISKFLAG_WANTED; 197 wakeup(dp); 198 } 199 200 return(error); 201} 202 203static int 204diskclose(dev_t dev, int fflag, int devtype, struct proc *p) 205{ 206 struct disk *dp; 207 int error; 208 209 error = 0; 210 dp = dev->si_disk; 211 dsclose(dev, devtype, dp->d_slice); 212 if (!dsisopen(dp->d_slice)) { 213 error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p); 214 } 215 return (error); 216} 217 218static void 219diskstrategy(struct bio *bp) 220{ 221 dev_t pdev; 222 struct disk *dp; 223 224 dp = bp->bio_dev->si_disk; 225 if (!dp) { 226 pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART); 227 dp = bp->bio_dev->si_disk = pdev->si_disk; 228 bp->bio_dev->si_drv1 = pdev->si_drv1; 229 bp->bio_dev->si_drv2 = pdev->si_drv2; 230 bp->bio_dev->si_iosize_max = pdev->si_iosize_max; 231 bp->bio_dev->si_bsize_phys = pdev->si_bsize_phys; 232 bp->bio_dev->si_bsize_best = pdev->si_bsize_best; 233 } 234 235 if (!dp) { 236 bp->bio_error = ENXIO; 237 bp->bio_flags |= BIO_ERROR; 238 biodone(bp); 239 return; 240 } 241 242 if (dscheck(bp, dp->d_slice) <= 0) { 243 biodone(bp); 244 return; 245 } 246 247 KASSERT(dp->d_devsw != NULL, ("NULL devsw")); 248 KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy")); 249 dp->d_devsw->d_strategy(bp); 250 return; 251 252} 253 254static int 255diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) 256{ 257 struct disk *dp; 258 int error; 259 260 dp = dev->si_disk; 261 error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 262 if (error == ENOIOCTL) 263 error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p); 264 return (error); 265} 266 267static int 268diskpsize(dev_t dev) 269{ 270 struct disk *dp; 271 dev_t pdev; 272 273 dp = dev->si_disk; 274 if (!dp) { 275 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 276 dp = pdev->si_disk; 277 if (!dp) 278 return (-1); 279 dev->si_drv1 = pdev->si_drv1; 280 dev->si_drv2 = pdev->si_drv2; 281 /* XXX: don't set bp->b_dev->si_disk (?) */ 282 } 283 return (dssize(dev, &dp->d_slice)); 284} 285 286SYSCTL_DECL(_debug_sizeof); 287 288SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 289 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 290 291SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 292 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 293 294SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 295 0, sizeof(struct disk), "sizeof(struct disk)"); 296