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