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$ 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 <machine/md_var.h> 22 23 MALLOC_DEFINE(M_DISK, "disk", "disk data"); 24 25 static d_strategy_t diskstrategy; 26 static d_open_t diskopen; 27 static d_close_t diskclose; 28 static d_ioctl_t diskioctl; 29 static d_psize_t diskpsize; 30 31 static LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist); 32 33 dev_t 34 disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto) 35 { 36 dev_t dev; 37 38 bzero(dp, sizeof(*dp)); 39 40 dev = makedev(cdevsw->d_maj, 0); 41 if (!devsw(dev)) { 42 *proto = *cdevsw; 43 proto->d_open = diskopen; 44 proto->d_close = diskclose; 45 proto->d_ioctl = diskioctl; 46 proto->d_strategy = diskstrategy; 47 proto->d_psize = diskpsize; 48 cdevsw_add(proto); 49 } 50 51 if (bootverbose) 52 printf("Creating DISK %s%d\n", cdevsw->d_name, unit); 53 dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART), 54 0, 0, 0, "%s%d", cdevsw->d_name, unit); 55 56 dev->si_disk = dp; 57 dp->d_dev = dev; 58 dp->d_dsflags = flags; 59 dp->d_devsw = cdevsw; 60 LIST_INSERT_HEAD(&disklist, dp, d_list); 61 return (dev); 62 } 63 64 int 65 disk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize) 66 { 67 struct disk *dp; 68 struct disklabel *dl; 69 u_int boff; 70 71 dp = dev->si_disk; 72 if (!dp) 73 return (ENXIO); 74 if (!dp->d_slice) 75 return (ENXIO); 76 dl = dsgetlabel(dev, dp->d_slice); 77 if (!dl) 78 return (ENXIO); 79 *count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize; 80 if (dumplo < 0 || 81 (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size)) 82 return (EINVAL); 83 boff = dl->d_partitions[dkpart(dev)].p_offset + 84 dp->d_slice->dss_slices[dkslice(dev)].ds_offset; 85 *blkno = boff + dumplo; 86 *secsize = dl->d_secsize; 87 return (0); 88 89 } 90 91 void 92 disk_invalidate (struct disk *disk) 93 { 94 if (disk->d_slice) 95 dsgone(&disk->d_slice); 96 } 97 98 void 99 disk_destroy(dev_t dev) 100 { 101 LIST_REMOVE(dev->si_disk, d_list); 102 bzero(dev->si_disk, sizeof(*dev->si_disk)); 103 dev->si_disk = NULL; 104 destroy_dev(dev); 105 return; 106 } 107 108 struct disk * 109 disk_enumerate(struct disk *disk) 110 { 111 if (!disk) 112 return (LIST_FIRST(&disklist)); 113 else 114 return (LIST_NEXT(disk, d_list)); 115 } 116 117 /* 118 * The cdevsw functions 119 */ 120 121 static int 122 diskopen(dev_t dev, int oflags, int devtype, struct proc *p) 123 { 124 dev_t pdev; 125 struct disk *dp; 126 int error; 127 128 error = 0; 129 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 130 131 dp = pdev->si_disk; 132 if (!dp) 133 return (ENXIO); 134 135 while (dp->d_flags & DISKFLAG_LOCK) { 136 dp->d_flags |= DISKFLAG_WANTED; 137 error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz); 138 if (error) 139 return (error); 140 } 141 dp->d_flags |= DISKFLAG_LOCK; 142 143 if (!dsisopen(dp->d_slice)) { 144 if (!pdev->si_iosize_max) 145 pdev->si_iosize_max = dev->si_iosize_max; 146 error = dp->d_devsw->d_open(pdev, oflags, devtype, p); 147 } 148 149 /* Inherit properties from the whole/raw dev_t */ 150 dev->si_disk = pdev->si_disk; 151 dev->si_drv1 = pdev->si_drv1; 152 dev->si_drv2 = pdev->si_drv2; 153 dev->si_iosize_max = pdev->si_iosize_max; 154 dev->si_bsize_phys = pdev->si_bsize_phys; 155 dev->si_bsize_best = pdev->si_bsize_best; 156 157 if (error) 158 goto out; 159 160 error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label); 161 162 if (!dsisopen(dp->d_slice)) 163 dp->d_devsw->d_close(pdev, oflags, devtype, p); 164 out: 165 dp->d_flags &= ~DISKFLAG_LOCK; 166 if (dp->d_flags & DISKFLAG_WANTED) { 167 dp->d_flags &= ~DISKFLAG_WANTED; 168 wakeup(dp); 169 } 170 171 return(error); 172 } 173 174 static int 175 diskclose(dev_t dev, int fflag, int devtype, struct proc *p) 176 { 177 struct disk *dp; 178 int error; 179 180 error = 0; 181 dp = dev->si_disk; 182 dsclose(dev, devtype, dp->d_slice); 183 if (!dsisopen(dp->d_slice)) { 184 error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p); 185 } 186 return (error); 187 } 188 189 static void 190 diskstrategy(struct bio *bp) 191 { 192 dev_t pdev; 193 struct disk *dp; 194 195 dp = bp->bio_dev->si_disk; 196 if (!dp) { 197 pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART); 198 dp = bp->bio_dev->si_disk = pdev->si_disk; 199 bp->bio_dev->si_drv1 = pdev->si_drv1; 200 bp->bio_dev->si_drv2 = pdev->si_drv2; 201 bp->bio_dev->si_iosize_max = pdev->si_iosize_max; 202 bp->bio_dev->si_bsize_phys = pdev->si_bsize_phys; 203 bp->bio_dev->si_bsize_best = pdev->si_bsize_best; 204 } 205 206 if (!dp) { 207 bp->bio_error = ENXIO; 208 bp->bio_flags |= BIO_ERROR; 209 biodone(bp); 210 return; 211 } 212 213 if (dscheck(bp, dp->d_slice) <= 0) { 214 biodone(bp); 215 return; 216 } 217 218 KASSERT(dp->d_devsw != NULL, ("NULL devsw")); 219 KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy")); 220 dp->d_devsw->d_strategy(bp); 221 return; 222 223 } 224 225 static int 226 diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) 227 { 228 struct disk *dp; 229 int error; 230 231 dp = dev->si_disk; 232 error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 233 if (error == ENOIOCTL) 234 error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p); 235 return (error); 236 } 237 238 static int 239 diskpsize(dev_t dev) 240 { 241 struct disk *dp; 242 dev_t pdev; 243 244 dp = dev->si_disk; 245 if (!dp) { 246 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 247 dp = pdev->si_disk; 248 if (!dp) 249 return (-1); 250 dev->si_drv1 = pdev->si_drv1; 251 dev->si_drv2 = pdev->si_drv2; 252 /* XXX: don't set bp->b_dev->si_disk (?) */ 253 } 254 return (dssize(dev, &dp->d_slice)); 255 } 256 257 SYSCTL_DECL(_debug_sizeof); 258 259 SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 260 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 261 262 SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 263 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 264 265 SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 266 0, sizeof(struct disk), "sizeof(struct disk)"); 267