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 <sys/sysctl.h> 22 #include <machine/md_var.h> 23 #include <sys/ctype.h> 24 25 MALLOC_DEFINE(M_DISK, "disk", "disk data"); 26 27 static d_strategy_t diskstrategy; 28 static d_open_t diskopen; 29 static d_close_t diskclose; 30 static d_ioctl_t diskioctl; 31 static d_psize_t diskpsize; 32 33 static LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist); 34 35 static void 36 disk_clone(void *arg, char *name, int namelen, dev_t *dev) 37 { 38 struct disk *dp; 39 char const *d; 40 int i, u, s, p; 41 dev_t pdev; 42 43 if (*dev != NODEV) 44 return; 45 46 LIST_FOREACH(dp, &disklist, d_list) { 47 d = dp->d_devsw->d_name; 48 i = strlen(d); 49 if (bcmp(d, name, i) != 0) 50 continue; 51 u = 0; 52 if (!isdigit(name[i])) 53 continue; 54 while (isdigit(name[i])) { 55 u *= 10; 56 u += name[i++] - '0'; 57 } 58 p = RAW_PART; 59 s = WHOLE_DISK_SLICE; 60 pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p)); 61 if (pdev->si_disk == NULL) 62 continue; 63 if (name[i] != '\0') { 64 if (name[i] == 's') { 65 s = 0; 66 i++; 67 if (!isdigit(name[i])) 68 continue; 69 while (isdigit(name[i])) { 70 s *= 10; 71 s += name[i++] - '0'; 72 } 73 s += BASE_SLICE - 1; 74 } else { 75 s = COMPATIBILITY_SLICE; 76 } 77 if (name[i] == '\0') 78 ; 79 else if (name[i] < 'a' || name[i] > 'h') 80 continue; 81 else 82 p = name[i] - 'a'; 83 } 84 85 *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 86 UID_ROOT, GID_OPERATOR, 0640, name); 87 return; 88 } 89 } 90 91 static void 92 inherit_raw(dev_t pdev, dev_t dev) 93 { 94 dev->si_disk = pdev->si_disk; 95 dev->si_drv1 = pdev->si_drv1; 96 dev->si_drv2 = pdev->si_drv2; 97 dev->si_iosize_max = pdev->si_iosize_max; 98 dev->si_bsize_phys = pdev->si_bsize_phys; 99 dev->si_bsize_best = pdev->si_bsize_best; 100 } 101 102 dev_t 103 disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto) 104 { 105 static int once; 106 dev_t dev; 107 108 bzero(dp, sizeof(*dp)); 109 110 dev = makedev(cdevsw->d_maj, 0); 111 if (!devsw(dev)) { 112 *proto = *cdevsw; 113 proto->d_open = diskopen; 114 proto->d_close = diskclose; 115 proto->d_ioctl = diskioctl; 116 proto->d_strategy = diskstrategy; 117 proto->d_psize = diskpsize; 118 cdevsw_add(proto); 119 } 120 121 if (bootverbose) 122 printf("Creating DISK %s%d\n", cdevsw->d_name, unit); 123 dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART), 124 UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit); 125 126 dev->si_disk = dp; 127 dp->d_dev = dev; 128 dp->d_dsflags = flags; 129 dp->d_devsw = cdevsw; 130 LIST_INSERT_HEAD(&disklist, dp, d_list); 131 if (!once) { 132 EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000); 133 once++; 134 } 135 return (dev); 136 } 137 138 int 139 disk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize) 140 { 141 struct disk *dp; 142 struct disklabel *dl; 143 u_int boff; 144 145 dp = dev->si_disk; 146 if (!dp) 147 return (ENXIO); 148 if (!dp->d_slice) 149 return (ENXIO); 150 dl = dsgetlabel(dev, dp->d_slice); 151 if (!dl) 152 return (ENXIO); 153 *count = (u_long)Maxmem * PAGE_SIZE / dl->d_secsize; 154 if (dumplo < 0 || 155 (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size)) 156 return (EINVAL); 157 boff = dl->d_partitions[dkpart(dev)].p_offset + 158 dp->d_slice->dss_slices[dkslice(dev)].ds_offset; 159 *blkno = boff + dumplo; 160 *secsize = dl->d_secsize; 161 return (0); 162 163 } 164 165 void 166 disk_invalidate (struct disk *disk) 167 { 168 if (disk->d_slice) 169 dsgone(&disk->d_slice); 170 } 171 172 void 173 disk_destroy(dev_t dev) 174 { 175 LIST_REMOVE(dev->si_disk, d_list); 176 bzero(dev->si_disk, sizeof(*dev->si_disk)); 177 dev->si_disk = NULL; 178 destroy_dev(dev); 179 return; 180 } 181 182 struct disk * 183 disk_enumerate(struct disk *disk) 184 { 185 if (!disk) 186 return (LIST_FIRST(&disklist)); 187 else 188 return (LIST_NEXT(disk, d_list)); 189 } 190 191 static int 192 sysctl_disks(SYSCTL_HANDLER_ARGS) 193 { 194 struct disk *disk; 195 int error, first; 196 197 disk = NULL; 198 first = 1; 199 200 while ((disk = disk_enumerate(disk))) { 201 if (!first) { 202 error = SYSCTL_OUT(req, " ", 1); 203 if (error) 204 return error; 205 } else { 206 first = 0; 207 } 208 error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name)); 209 if (error) 210 return error; 211 } 212 error = SYSCTL_OUT(req, "", 1); 213 return error; 214 } 215 216 SYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL, 217 sysctl_disks, "A", "names of available disks"); 218 219 /* 220 * The cdevsw functions 221 */ 222 223 static int 224 diskopen(dev_t dev, int oflags, int devtype, struct proc *p) 225 { 226 dev_t pdev; 227 struct disk *dp; 228 int error; 229 230 error = 0; 231 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 232 233 dp = pdev->si_disk; 234 if (!dp) 235 return (ENXIO); 236 237 while (dp->d_flags & DISKFLAG_LOCK) { 238 dp->d_flags |= DISKFLAG_WANTED; 239 error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz); 240 if (error) 241 return (error); 242 } 243 dp->d_flags |= DISKFLAG_LOCK; 244 245 if (!dsisopen(dp->d_slice)) { 246 if (!pdev->si_iosize_max) 247 pdev->si_iosize_max = dev->si_iosize_max; 248 error = dp->d_devsw->d_open(pdev, oflags, devtype, p); 249 } 250 251 /* Inherit properties from the whole/raw dev_t */ 252 inherit_raw(pdev, dev); 253 254 if (error) 255 goto out; 256 257 error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label); 258 259 if (!dsisopen(dp->d_slice)) 260 dp->d_devsw->d_close(pdev, oflags, devtype, p); 261 out: 262 dp->d_flags &= ~DISKFLAG_LOCK; 263 if (dp->d_flags & DISKFLAG_WANTED) { 264 dp->d_flags &= ~DISKFLAG_WANTED; 265 wakeup(dp); 266 } 267 268 return(error); 269 } 270 271 static int 272 diskclose(dev_t dev, int fflag, int devtype, struct proc *p) 273 { 274 struct disk *dp; 275 int error; 276 dev_t pdev; 277 278 error = 0; 279 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 280 dp = pdev->si_disk; 281 dsclose(dev, devtype, dp->d_slice); 282 if (!dsisopen(dp->d_slice)) { 283 error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, p); 284 } 285 return (error); 286 } 287 288 static void 289 diskstrategy(struct bio *bp) 290 { 291 dev_t pdev; 292 struct disk *dp; 293 294 pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART); 295 dp = pdev->si_disk; 296 if (dp != bp->bio_dev->si_disk) 297 inherit_raw(pdev, bp->bio_dev); 298 299 if (!dp) { 300 bp->bio_error = ENXIO; 301 bp->bio_flags |= BIO_ERROR; 302 biodone(bp); 303 return; 304 } 305 306 if (dscheck(bp, dp->d_slice) <= 0) { 307 biodone(bp); 308 return; 309 } 310 311 KASSERT(dp->d_devsw != NULL, ("NULL devsw")); 312 KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy")); 313 dp->d_devsw->d_strategy(bp); 314 return; 315 316 } 317 318 static int 319 diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) 320 { 321 struct disk *dp; 322 int error; 323 dev_t pdev; 324 325 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 326 dp = pdev->si_disk; 327 error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 328 if (error == ENOIOCTL) 329 error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, p); 330 return (error); 331 } 332 333 static int 334 diskpsize(dev_t dev) 335 { 336 struct disk *dp; 337 dev_t pdev; 338 339 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 340 dp = pdev->si_disk; 341 if (!dp) 342 return (-1); 343 if (dp != dev->si_disk) { 344 dev->si_drv1 = pdev->si_drv1; 345 dev->si_drv2 = pdev->si_drv2; 346 /* XXX: don't set bp->b_dev->si_disk (?) */ 347 } 348 return (dssize(dev, &dp->d_slice)); 349 } 350 351 SYSCTL_DECL(_debug_sizeof); 352 353 SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 354 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 355 356 SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 357 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 358 359 SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 360 0, sizeof(struct disk), "sizeof(struct disk)"); 361