1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 2912 artem * Common Development and Distribution License (the "License"). 6 2912 artem * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 9956 William * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel 27 0 stevel /* 28 0 stevel * Ramdisk device driver. 29 0 stevel * 30 0 stevel * There are two types of ramdisk: 'real' OBP-created ramdisks, and 'pseudo' 31 0 stevel * ramdisks created at runtime with no corresponding OBP device node. The 32 0 stevel * ramdisk(7D) driver is capable of dealing with both, and with the creation 33 0 stevel * and deletion of 'pseudo' ramdisks. 34 0 stevel * 35 0 stevel * Every ramdisk has a single 'state' structure which maintains data for 36 0 stevel * that ramdisk, and is assigned a single minor number. The bottom 10-bits 37 0 stevel * of the minor number index the state structures; the top 8-bits give a 38 0 stevel * 'real OBP disk' number, i.e. they are zero for 'pseudo' ramdisks. Thus 39 0 stevel * it is possible to distinguish 'real' from 'pseudo' ramdisks using the 40 0 stevel * top 8-bits of the minor number. 41 0 stevel * 42 0 stevel * Each OBP-created ramdisk has its own node in the device tree with an 43 0 stevel * "existing" property which describes the one-or-more physical address ranges 44 0 stevel * assigned to the ramdisk. All 'pseudo' ramdisks share a common devinfo 45 0 stevel * structure. 46 0 stevel * 47 0 stevel * A single character device node is used by ramdiskadm(1M) to communicate 48 0 stevel * with the ramdisk driver, with minor number 0: 49 0 stevel * 50 0 stevel * /dev/ramdiskctl -> /devices/pseudo/ramdisk@0:ctl 51 0 stevel * 52 0 stevel * For consistent access, block and raw device nodes are created for *every* 53 0 stevel * ramdisk. For 'pseudo' ramdisks: 54 0 stevel * 55 0 stevel * /dev/ramdisk/<diskname> -> /devices/pseudo/ramdisk@0:<diskname> 56 0 stevel * /dev/rramdisk/<diskname> -> /devices/pseudo/ramdisk@0:<diskname>,raw 57 0 stevel * 58 0 stevel * For OBP-created ramdisks: 59 0 stevel * 60 0 stevel * /dev/ramdisk/<diskname> -> /devices/ramdisk-<diskname>:a 61 0 stevel * /dev/ramdisk/<diskname> -> /devices/ramdisk-<diskname>:a,raw 62 0 stevel * 63 0 stevel * This allows the transition from the standalone to the kernel to proceed 64 0 stevel * when booting from a ramdisk, and for the installation to correctly identify 65 0 stevel * the root device. 66 0 stevel */ 67 0 stevel 68 0 stevel #include <sys/types.h> 69 0 stevel #include <sys/param.h> 70 0 stevel #include <sys/sysmacros.h> 71 0 stevel #include <sys/errno.h> 72 0 stevel #include <sys/uio.h> 73 0 stevel #include <sys/buf.h> 74 0 stevel #include <sys/modctl.h> 75 0 stevel #include <sys/open.h> 76 0 stevel #include <sys/kmem.h> 77 0 stevel #include <sys/poll.h> 78 0 stevel #include <sys/conf.h> 79 0 stevel #include <sys/cmn_err.h> 80 0 stevel #include <sys/stat.h> 81 0 stevel #include <sys/file.h> 82 0 stevel #include <sys/ddi.h> 83 0 stevel #include <sys/sunddi.h> 84 0 stevel #include <sys/ramdisk.h> 85 0 stevel #include <vm/seg_kmem.h> 86 9956 William 87 9956 William /* 88 9956 William * Flag to disable the use of real ramdisks (in the OBP - on Sparc) when 89 9956 William * the associated memory is no longer available - set in the bootops section. 90 9956 William */ 91 9956 William #ifdef __sparc 92 9956 William extern int bootops_obp_ramdisk_disabled; 93 9956 William #endif /* __sparc */ 94 0 stevel 95 0 stevel /* 96 0 stevel * An opaque handle where information about our set of ramdisk devices lives. 97 0 stevel */ 98 0 stevel static void *rd_statep; 99 0 stevel 100 0 stevel /* 101 0 stevel * Pointer to devinfo for the 'pseudo' ramdisks. Real OBP-created ramdisks 102 0 stevel * get their own individual devinfo. 103 0 stevel */ 104 0 stevel static dev_info_t *rd_dip = NULL; 105 0 stevel 106 0 stevel /* 107 0 stevel * Global state lock. 108 0 stevel */ 109 0 stevel static kmutex_t rd_lock; 110 0 stevel 111 0 stevel /* 112 0 stevel * Maximum number of ramdisks supported by this driver. 113 0 stevel */ 114 0 stevel static uint32_t rd_max_disks = RD_DFLT_DISKS; 115 0 stevel 116 0 stevel /* 117 0 stevel * Percentage of physical memory which can be assigned to pseudo ramdisks, 118 0 stevel * what that equates to in pages, and how many pages are currently assigned. 119 0 stevel */ 120 0 stevel static uint_t rd_percent_physmem = RD_DEFAULT_PERCENT_PHYSMEM; 121 0 stevel static pgcnt_t rd_max_physmem; 122 0 stevel static pgcnt_t rd_tot_physmem; 123 0 stevel 124 0 stevel static uint_t rd_maxphys = RD_DEFAULT_MAXPHYS; 125 0 stevel 126 0 stevel /* 127 0 stevel * Is the driver busy, i.e. are there any pseudo ramdisk devices in existence? 128 0 stevel */ 129 0 stevel static int 130 0 stevel rd_is_busy(void) 131 0 stevel { 132 0 stevel minor_t minor; 133 0 stevel rd_devstate_t *rsp; 134 0 stevel 135 0 stevel ASSERT(mutex_owned(&rd_lock)); 136 0 stevel for (minor = 1; minor <= rd_max_disks; ++minor) { 137 0 stevel if ((rsp = ddi_get_soft_state(rd_statep, minor)) != NULL && 138 0 stevel rsp->rd_dip == rd_dip) { 139 0 stevel return (EBUSY); 140 0 stevel } 141 0 stevel } 142 0 stevel return (0); 143 0 stevel } 144 0 stevel 145 0 stevel /* 146 0 stevel * Find the first free minor number; returns zero if there isn't one. 147 0 stevel */ 148 0 stevel static minor_t 149 0 stevel rd_find_free_minor(void) 150 0 stevel { 151 0 stevel minor_t minor; 152 0 stevel 153 0 stevel ASSERT(mutex_owned(&rd_lock)); 154 0 stevel for (minor = 1; minor <= rd_max_disks; ++minor) { 155 0 stevel if (ddi_get_soft_state(rd_statep, minor) == NULL) { 156 0 stevel return (minor); 157 0 stevel } 158 0 stevel } 159 0 stevel return (0); 160 0 stevel } 161 0 stevel 162 0 stevel /* 163 0 stevel * Locate the rd_devstate for the named ramdisk; returns NULL if not found. 164 0 stevel * Each ramdisk is identified uniquely by name, i.e. an OBP-created ramdisk 165 0 stevel * cannot have the same name as a pseudo ramdisk. 166 0 stevel */ 167 0 stevel static rd_devstate_t * 168 0 stevel rd_find_named_disk(char *name) 169 0 stevel { 170 0 stevel minor_t minor; 171 0 stevel rd_devstate_t *rsp; 172 0 stevel 173 0 stevel ASSERT(mutex_owned(&rd_lock)); 174 0 stevel for (minor = 1; minor <= rd_max_disks; ++minor) { 175 0 stevel if ((rsp = ddi_get_soft_state(rd_statep, minor)) != NULL && 176 0 stevel strcmp(rsp->rd_name, name) == 0) { 177 0 stevel return (rsp); 178 0 stevel } 179 0 stevel } 180 0 stevel return (NULL); 181 0 stevel } 182 0 stevel 183 0 stevel /* 184 0 stevel * Locate the rd_devstate for the real OBP-created ramdisk whose devinfo 185 0 stevel * is referenced by 'dip'; returns NULL if not found (shouldn't happen). 186 0 stevel */ 187 0 stevel static rd_devstate_t * 188 0 stevel rd_find_dip_state(dev_info_t *dip) 189 0 stevel { 190 0 stevel minor_t minor; 191 0 stevel rd_devstate_t *rsp; 192 0 stevel 193 0 stevel ASSERT(mutex_owned(&rd_lock)); 194 0 stevel for (minor = 1; minor <= rd_max_disks; ++minor) { 195 0 stevel if ((rsp = ddi_get_soft_state(rd_statep, minor)) != NULL && 196 0 stevel rsp->rd_dip == dip) { 197 0 stevel return (rsp); 198 0 stevel } 199 0 stevel } 200 0 stevel return (NULL); 201 0 stevel } 202 0 stevel 203 0 stevel /* 204 0 stevel * Is the ramdisk open? 205 0 stevel */ 206 0 stevel static int 207 0 stevel rd_is_open(rd_devstate_t *rsp) 208 0 stevel { 209 0 stevel ASSERT(mutex_owned(&rd_lock)); 210 0 stevel return (rsp->rd_chr_open || rsp->rd_blk_open || rsp->rd_lyr_open_cnt); 211 0 stevel } 212 0 stevel 213 0 stevel /* 214 0 stevel * Mark the ramdisk open. 215 0 stevel */ 216 0 stevel static int 217 0 stevel rd_opened(rd_devstate_t *rsp, int otyp) 218 0 stevel { 219 0 stevel ASSERT(mutex_owned(&rd_lock)); 220 0 stevel switch (otyp) { 221 0 stevel case OTYP_CHR: 222 0 stevel rsp->rd_chr_open = 1; 223 0 stevel break; 224 0 stevel case OTYP_BLK: 225 0 stevel rsp->rd_blk_open = 1; 226 0 stevel break; 227 0 stevel case OTYP_LYR: 228 0 stevel rsp->rd_lyr_open_cnt++; 229 0 stevel break; 230 0 stevel default: 231 0 stevel return (-1); 232 0 stevel } 233 0 stevel return (0); 234 0 stevel } 235 0 stevel 236 0 stevel /* 237 0 stevel * Mark the ramdisk closed. 238 0 stevel */ 239 0 stevel static void 240 0 stevel rd_closed(rd_devstate_t *rsp, int otyp) 241 0 stevel { 242 0 stevel ASSERT(mutex_owned(&rd_lock)); 243 0 stevel switch (otyp) { 244 0 stevel case OTYP_CHR: 245 0 stevel rsp->rd_chr_open = 0; 246 0 stevel break; 247 0 stevel case OTYP_BLK: 248 0 stevel rsp->rd_blk_open = 0; 249 0 stevel break; 250 0 stevel case OTYP_LYR: 251 0 stevel rsp->rd_lyr_open_cnt--; 252 0 stevel break; 253 0 stevel default: 254 0 stevel break; 255 0 stevel } 256 0 stevel } 257 0 stevel 258 0 stevel static void 259 0 stevel rd_init_tuneables(void) 260 0 stevel { 261 0 stevel char *prop, *p; 262 0 stevel 263 0 stevel /* 264 0 stevel * Ensure sanity of 'rd_max_disks', which may be tuned in ramdisk.conf. 265 0 stevel */ 266 0 stevel if (ddi_prop_lookup_string(DDI_DEV_T_ANY, rd_dip, 0, 267 0 stevel "max_disks", &prop) == DDI_PROP_SUCCESS) { 268 0 stevel p = prop; 269 0 stevel rd_max_disks = (uint32_t)stoi(&p); 270 0 stevel ddi_prop_free(prop); 271 0 stevel } 272 0 stevel if (rd_max_disks >= RD_MAX_DISKS) { 273 0 stevel cmn_err(CE_WARN, "ramdisk: rd_max_disks (%u) too big;" 274 0 stevel " using default (%u).", rd_max_disks, RD_MAX_DISKS - 1); 275 0 stevel 276 0 stevel rd_max_disks = RD_MAX_DISKS - 1; 277 0 stevel } 278 0 stevel 279 0 stevel /* 280 0 stevel * Ensure sanity of 'rd_percent_physmem', which may be tuned 281 0 stevel * in ramdisk.conf. 282 0 stevel */ 283 0 stevel if (ddi_prop_lookup_string(DDI_DEV_T_ANY, rd_dip, 0, 284 0 stevel "percent_physmem", &prop) == DDI_PROP_SUCCESS) { 285 0 stevel p = prop; 286 0 stevel rd_percent_physmem = (uint_t)stoi(&p); 287 0 stevel ddi_prop_free(prop); 288 0 stevel } 289 0 stevel if (rd_percent_physmem >= 100) { 290 0 stevel cmn_err(CE_WARN, "ramdisk: rd_percent_physmem (%u) >= 100;" 291 0 stevel " using default (%u%%).", rd_percent_physmem, 292 0 stevel RD_DEFAULT_PERCENT_PHYSMEM); 293 0 stevel 294 0 stevel rd_percent_physmem = RD_DEFAULT_PERCENT_PHYSMEM; 295 0 stevel } 296 0 stevel 297 0 stevel /* 298 4363 blakej * Since availrmem_initial is a long, this won't overflow. 299 0 stevel */ 300 4363 blakej rd_max_physmem = (availrmem_initial * rd_percent_physmem) / 100; 301 0 stevel } 302 0 stevel 303 0 stevel /* 304 4363 blakej * Allocate enough physical pages to hold "npages" pages. Returns an 305 0 stevel * array of page_t * pointers that can later be mapped in or out via 306 0 stevel * rd_{un}map_window() but is otherwise opaque, or NULL on failure. 307 0 stevel */ 308 0 stevel page_t ** 309 0 stevel rd_phys_alloc(pgcnt_t npages) 310 0 stevel { 311 0 stevel page_t *pp, **ppa; 312 4363 blakej spgcnt_t i; 313 4363 blakej size_t ppalen; 314 0 stevel struct seg kseg; 315 4363 blakej caddr_t addr; /* For coloring */ 316 0 stevel 317 4363 blakej if (rd_tot_physmem + npages > rd_max_physmem) 318 4363 blakej return (NULL); 319 4363 blakej 320 4363 blakej if (!page_resv(npages, KM_NOSLEEP)) 321 4363 blakej return (NULL); 322 4363 blakej 323 4363 blakej if (!page_create_wait(npages, 0)) { 324 4363 blakej page_unresv(npages); 325 0 stevel return (NULL); 326 0 stevel } 327 0 stevel 328 4363 blakej ppalen = npages * sizeof (struct page_t *); 329 4363 blakej ppa = kmem_zalloc(ppalen, KM_NOSLEEP); 330 4363 blakej if (ppa == NULL) { 331 4363 blakej page_create_putback(npages); 332 4363 blakej page_unresv(npages); 333 4363 blakej return (NULL); 334 4363 blakej } 335 4363 blakej 336 4363 blakej kseg.s_as = &kas; 337 0 stevel for (i = 0, addr = NULL; i < npages; ++i, addr += PAGESIZE) { 338 4363 blakej pp = page_get_freelist(&kvp, 0, &kseg, addr, PAGESIZE, 0, NULL); 339 4363 blakej if (pp == NULL) { 340 4363 blakej pp = page_get_cachelist(&kvp, 0, &kseg, addr, 0, NULL); 341 4363 blakej if (pp == NULL) 342 0 stevel goto out; 343 4363 blakej if (!PP_ISAGED(pp)) 344 0 stevel page_hashout(pp, NULL); 345 0 stevel } 346 0 stevel 347 0 stevel PP_CLRFREE(pp); 348 0 stevel PP_CLRAGED(pp); 349 0 stevel ppa[i] = pp; 350 0 stevel } 351 4363 blakej 352 4363 blakej for (i = 0; i < npages; i++) 353 4363 blakej page_downgrade(ppa[i]); 354 0 stevel rd_tot_physmem += npages; 355 0 stevel 356 0 stevel return (ppa); 357 4363 blakej 358 0 stevel out: 359 4363 blakej ASSERT(i < npages); 360 4363 blakej page_create_putback(npages - i); 361 4363 blakej while (--i >= 0) 362 0 stevel page_free(ppa[i], 0); 363 0 stevel kmem_free(ppa, ppalen); 364 0 stevel page_unresv(npages); 365 0 stevel 366 0 stevel return (NULL); 367 0 stevel } 368 0 stevel 369 0 stevel /* 370 0 stevel * Free physical pages previously allocated via rd_phys_alloc(); note that 371 0 stevel * this function may block as it has to wait until it can exclusively lock 372 0 stevel * all the pages first. 373 0 stevel */ 374 0 stevel static void 375 0 stevel rd_phys_free(page_t **ppa, pgcnt_t npages) 376 0 stevel { 377 0 stevel pgcnt_t i; 378 0 stevel size_t ppalen = npages * sizeof (struct page_t *); 379 0 stevel 380 0 stevel for (i = 0; i < npages; ++i) { 381 0 stevel if (! page_tryupgrade(ppa[i])) { 382 0 stevel page_unlock(ppa[i]); 383 0 stevel while (! page_lock(ppa[i], SE_EXCL, NULL, P_RECLAIM)) 384 0 stevel ; 385 0 stevel } 386 0 stevel page_free(ppa[i], 0); 387 0 stevel } 388 0 stevel 389 0 stevel kmem_free(ppa, ppalen); 390 0 stevel 391 0 stevel page_unresv(npages); 392 0 stevel rd_tot_physmem -= npages; 393 0 stevel } 394 0 stevel 395 0 stevel /* 396 0 stevel * Remove a window mapping (if present). 397 0 stevel */ 398 0 stevel static void 399 0 stevel rd_unmap_window(rd_devstate_t *rsp) 400 0 stevel { 401 5648 setje ASSERT(rsp->rd_window_obp == 0); 402 0 stevel if (rsp->rd_window_base != RD_WINDOW_NOT_MAPPED) { 403 0 stevel hat_unload(kas.a_hat, rsp->rd_window_virt, rsp->rd_window_size, 404 0 stevel HAT_UNLOAD_UNLOCK); 405 0 stevel } 406 0 stevel } 407 0 stevel 408 0 stevel /* 409 0 stevel * Map a portion of the ramdisk into the virtual window. 410 0 stevel */ 411 0 stevel static void 412 0 stevel rd_map_window(rd_devstate_t *rsp, off_t offset) 413 0 stevel { 414 0 stevel pgcnt_t offpgs = btop(offset); 415 0 stevel 416 0 stevel if (rsp->rd_window_base != RD_WINDOW_NOT_MAPPED) { 417 0 stevel /* 418 0 stevel * Already mapped; is offset within our window? 419 0 stevel */ 420 0 stevel if (offset >= rsp->rd_window_base && 421 0 stevel offset < rsp->rd_window_base + rsp->rd_window_size) { 422 0 stevel return; 423 0 stevel } 424 0 stevel 425 0 stevel /* 426 0 stevel * No, we need to re-map; toss the old mapping. 427 0 stevel */ 428 0 stevel rd_unmap_window(rsp); 429 0 stevel } 430 0 stevel rsp->rd_window_base = ptob(offpgs); 431 0 stevel 432 0 stevel /* 433 0 stevel * Different algorithms depending on whether this is a real 434 0 stevel * OBP-created ramdisk, or a pseudo ramdisk. 435 0 stevel */ 436 0 stevel if (rsp->rd_dip == rd_dip) { 437 0 stevel pgcnt_t pi, lastpi; 438 0 stevel caddr_t vaddr; 439 0 stevel 440 0 stevel /* 441 0 stevel * Find the range of pages which should be mapped. 442 0 stevel */ 443 0 stevel pi = offpgs; 444 0 stevel lastpi = pi + btopr(rsp->rd_window_size); 445 0 stevel if (lastpi > rsp->rd_npages) { 446 0 stevel lastpi = rsp->rd_npages; 447 0 stevel } 448 0 stevel 449 0 stevel /* 450 0 stevel * Load the mapping. 451 0 stevel */ 452 0 stevel vaddr = rsp->rd_window_virt; 453 0 stevel for (; pi < lastpi; ++pi) { 454 0 stevel hat_memload(kas.a_hat, vaddr, rsp->rd_ppa[pi], 455 0 stevel (PROT_READ | PROT_WRITE) | HAT_NOSYNC, 456 0 stevel HAT_LOAD_LOCK); 457 0 stevel vaddr += ptob(1); 458 0 stevel } 459 0 stevel } else { 460 0 stevel uint_t i; 461 0 stevel pfn_t pfn; 462 0 stevel 463 0 stevel /* 464 0 stevel * Real OBP-created ramdisk: locate the physical range which 465 0 stevel * contains this offset. 466 0 stevel */ 467 0 stevel for (i = 0; i < rsp->rd_nexisting; ++i) { 468 0 stevel if (offset < rsp->rd_existing[i].size) { 469 0 stevel break; 470 0 stevel } 471 0 stevel offset -= rsp->rd_existing[i].size; 472 0 stevel } 473 0 stevel ASSERT(i < rsp->rd_nexisting); 474 0 stevel 475 0 stevel /* 476 0 stevel * Load the mapping. 477 0 stevel */ 478 0 stevel pfn = btop(rsp->rd_existing[i].phys + offset); 479 0 stevel hat_devload(kas.a_hat, rsp->rd_window_virt, rsp->rd_window_size, 480 0 stevel pfn, (PROT_READ | PROT_WRITE), 481 0 stevel HAT_LOAD_NOCONSIST | HAT_LOAD_LOCK); 482 0 stevel } 483 0 stevel } 484 0 stevel 485 0 stevel /* 486 0 stevel * Fakes up a disk geometry, and one big partition, based on the size 487 0 stevel * of the file. This is needed because we allow newfs'ing the device, 488 0 stevel * and newfs will do several disk ioctls to figure out the geometry and 489 0 stevel * partition information. It uses that information to determine the parameters 490 3517 mp204432 * to pass to mkfs. Geometry is pretty much irrelevant these days, but we 491 0 stevel * have to support it. 492 0 stevel * 493 0 stevel * Stolen from lofi.c - should maybe split out common code sometime. 494 0 stevel */ 495 0 stevel static void 496 0 stevel rd_fake_disk_geometry(rd_devstate_t *rsp) 497 0 stevel { 498 0 stevel /* dk_geom - see dkio(7I) */ 499 0 stevel /* 500 0 stevel * dkg_ncyl _could_ be set to one here (one big cylinder with gobs 501 0 stevel * of sectors), but that breaks programs like fdisk which want to 502 0 stevel * partition a disk by cylinder. With one cylinder, you can't create 503 0 stevel * an fdisk partition and put pcfs on it for testing (hard to pick 504 0 stevel * a number between one and one). 505 0 stevel * 506 0 stevel * The cheezy floppy test is an attempt to not have too few cylinders 507 0 stevel * for a small file, or so many on a big file that you waste space 508 0 stevel * for backup superblocks or cylinder group structures. 509 0 stevel */ 510 0 stevel if (rsp->rd_size < (2 * 1024 * 1024)) /* floppy? */ 511 0 stevel rsp->rd_dkg.dkg_ncyl = rsp->rd_size / (100 * 1024); 512 0 stevel else 513 0 stevel rsp->rd_dkg.dkg_ncyl = rsp->rd_size / (300 * 1024); 514 0 stevel /* in case file file is < 100k */ 515 0 stevel if (rsp->rd_dkg.dkg_ncyl == 0) 516 0 stevel rsp->rd_dkg.dkg_ncyl = 1; 517 0 stevel rsp->rd_dkg.dkg_acyl = 0; 518 0 stevel rsp->rd_dkg.dkg_bcyl = 0; 519 0 stevel rsp->rd_dkg.dkg_nhead = 1; 520 0 stevel rsp->rd_dkg.dkg_obs1 = 0; 521 0 stevel rsp->rd_dkg.dkg_intrlv = 0; 522 0 stevel rsp->rd_dkg.dkg_obs2 = 0; 523 0 stevel rsp->rd_dkg.dkg_obs3 = 0; 524 0 stevel rsp->rd_dkg.dkg_apc = 0; 525 0 stevel rsp->rd_dkg.dkg_rpm = 7200; 526 0 stevel rsp->rd_dkg.dkg_pcyl = rsp->rd_dkg.dkg_ncyl + rsp->rd_dkg.dkg_acyl; 527 0 stevel rsp->rd_dkg.dkg_nsect = rsp->rd_size / 528 0 stevel (DEV_BSIZE * rsp->rd_dkg.dkg_ncyl); 529 0 stevel rsp->rd_dkg.dkg_write_reinstruct = 0; 530 0 stevel rsp->rd_dkg.dkg_read_reinstruct = 0; 531 0 stevel 532 0 stevel /* vtoc - see dkio(7I) */ 533 0 stevel bzero(&rsp->rd_vtoc, sizeof (struct vtoc)); 534 0 stevel rsp->rd_vtoc.v_sanity = VTOC_SANE; 535 0 stevel rsp->rd_vtoc.v_version = V_VERSION; 536 0 stevel bcopy(RD_DRIVER_NAME, rsp->rd_vtoc.v_volume, 7); 537 0 stevel rsp->rd_vtoc.v_sectorsz = DEV_BSIZE; 538 0 stevel rsp->rd_vtoc.v_nparts = 1; 539 0 stevel rsp->rd_vtoc.v_part[0].p_tag = V_UNASSIGNED; 540 0 stevel rsp->rd_vtoc.v_part[0].p_flag = V_UNMNT; 541 0 stevel rsp->rd_vtoc.v_part[0].p_start = (daddr_t)0; 542 0 stevel /* 543 0 stevel * The partition size cannot just be the number of sectors, because 544 0 stevel * that might not end on a cylinder boundary. And if that's the case, 545 0 stevel * newfs/mkfs will print a scary warning. So just figure the size 546 0 stevel * based on the number of cylinders and sectors/cylinder. 547 0 stevel */ 548 0 stevel rsp->rd_vtoc.v_part[0].p_size = rsp->rd_dkg.dkg_pcyl * 549 0 stevel rsp->rd_dkg.dkg_nsect * rsp->rd_dkg.dkg_nhead; 550 0 stevel 551 0 stevel /* dk_cinfo - see dkio(7I) */ 552 0 stevel bzero(&rsp->rd_ci, sizeof (struct dk_cinfo)); 553 0 stevel (void) strcpy(rsp->rd_ci.dki_cname, RD_DRIVER_NAME); 554 0 stevel rsp->rd_ci.dki_ctype = DKC_MD; 555 0 stevel rsp->rd_ci.dki_flags = 0; 556 0 stevel rsp->rd_ci.dki_cnum = 0; 557 0 stevel rsp->rd_ci.dki_addr = 0; 558 0 stevel rsp->rd_ci.dki_space = 0; 559 0 stevel rsp->rd_ci.dki_prio = 0; 560 0 stevel rsp->rd_ci.dki_vec = 0; 561 0 stevel (void) strcpy(rsp->rd_ci.dki_dname, RD_DRIVER_NAME); 562 0 stevel rsp->rd_ci.dki_unit = 0; 563 0 stevel rsp->rd_ci.dki_slave = 0; 564 0 stevel rsp->rd_ci.dki_partition = 0; 565 0 stevel /* 566 0 stevel * newfs uses this to set maxcontig. Must not be < 16, or it 567 0 stevel * will be 0 when newfs multiplies it by DEV_BSIZE and divides 568 0 stevel * it by the block size. Then tunefs doesn't work because 569 0 stevel * maxcontig is 0. 570 0 stevel */ 571 0 stevel rsp->rd_ci.dki_maxtransfer = 16; 572 0 stevel } 573 0 stevel 574 0 stevel /* 575 0 stevel * Deallocate resources (virtual and physical, device nodes, structures) 576 0 stevel * from a ramdisk. 577 0 stevel */ 578 0 stevel static void 579 0 stevel rd_dealloc_resources(rd_devstate_t *rsp) 580 0 stevel { 581 0 stevel dev_info_t *dip = rsp->rd_dip; 582 0 stevel char namebuf[RD_NAME_LEN + 5]; 583 0 stevel dev_t fulldev; 584 0 stevel 585 5648 setje if (rsp->rd_window_obp == 0 && rsp->rd_window_virt != NULL) { 586 0 stevel if (rsp->rd_window_base != RD_WINDOW_NOT_MAPPED) { 587 0 stevel rd_unmap_window(rsp); 588 0 stevel } 589 0 stevel vmem_free(heap_arena, rsp->rd_window_virt, rsp->rd_window_size); 590 0 stevel } 591 0 stevel mutex_destroy(&rsp->rd_device_lock); 592 0 stevel 593 0 stevel if (rsp->rd_existing) { 594 0 stevel ddi_prop_free(rsp->rd_existing); 595 0 stevel } 596 0 stevel if (rsp->rd_ppa != NULL) { 597 0 stevel rd_phys_free(rsp->rd_ppa, rsp->rd_npages); 598 0 stevel } 599 0 stevel 600 0 stevel /* 601 0 stevel * Remove the block and raw device nodes. 602 0 stevel */ 603 0 stevel if (dip == rd_dip) { 604 0 stevel (void) snprintf(namebuf, sizeof (namebuf), "%s", 605 0 stevel rsp->rd_name); 606 0 stevel ddi_remove_minor_node(dip, namebuf); 607 0 stevel (void) snprintf(namebuf, sizeof (namebuf), "%s,raw", 608 0 stevel rsp->rd_name); 609 0 stevel ddi_remove_minor_node(dip, namebuf); 610 0 stevel } else { 611 0 stevel ddi_remove_minor_node(dip, "a"); 612 0 stevel ddi_remove_minor_node(dip, "a,raw"); 613 0 stevel } 614 0 stevel 615 0 stevel /* 616 0 stevel * Remove the "Size" and "Nblocks" properties. 617 0 stevel */ 618 0 stevel fulldev = makedevice(ddi_driver_major(dip), rsp->rd_minor); 619 0 stevel (void) ddi_prop_remove(fulldev, dip, SIZE_PROP_NAME); 620 0 stevel (void) ddi_prop_remove(fulldev, dip, NBLOCKS_PROP_NAME); 621 0 stevel 622 0 stevel if (rsp->rd_kstat) { 623 0 stevel kstat_delete(rsp->rd_kstat); 624 0 stevel mutex_destroy(&rsp->rd_kstat_lock); 625 0 stevel } 626 0 stevel 627 0 stevel ddi_soft_state_free(rd_statep, rsp->rd_minor); 628 0 stevel } 629 0 stevel 630 0 stevel /* 631 0 stevel * Allocate resources (virtual and physical, device nodes, structures) 632 0 stevel * to a ramdisk. 633 0 stevel */ 634 0 stevel static rd_devstate_t * 635 5648 setje rd_alloc_resources(char *name, uint_t addr, size_t size, dev_info_t *dip) 636 0 stevel { 637 0 stevel minor_t minor; 638 0 stevel rd_devstate_t *rsp; 639 0 stevel char namebuf[RD_NAME_LEN + 5]; 640 0 stevel dev_t fulldev; 641 0 stevel int64_t Nblocks_prop_val; 642 0 stevel int64_t Size_prop_val; 643 0 stevel 644 0 stevel minor = rd_find_free_minor(); 645 0 stevel if (ddi_soft_state_zalloc(rd_statep, minor) == DDI_FAILURE) { 646 0 stevel return (NULL); 647 0 stevel } 648 0 stevel rsp = ddi_get_soft_state(rd_statep, minor); 649 0 stevel 650 0 stevel (void) strcpy(rsp->rd_name, name); 651 0 stevel rsp->rd_dip = dip; 652 0 stevel rsp->rd_minor = minor; 653 0 stevel rsp->rd_size = size; 654 0 stevel 655 0 stevel /* 656 0 stevel * Allocate virtual window onto ramdisk. 657 0 stevel */ 658 0 stevel mutex_init(&rsp->rd_device_lock, NULL, MUTEX_DRIVER, NULL); 659 5648 setje if (addr == 0) { 660 5648 setje rsp->rd_window_obp = 0; 661 5648 setje rsp->rd_window_base = RD_WINDOW_NOT_MAPPED; 662 5648 setje rsp->rd_window_size = PAGESIZE; 663 5648 setje rsp->rd_window_virt = vmem_alloc(heap_arena, 664 5648 setje rsp->rd_window_size, VM_SLEEP); 665 5648 setje if (rsp->rd_window_virt == NULL) { 666 5648 setje goto create_failed; 667 5648 setje } 668 5648 setje } else { 669 5648 setje rsp->rd_window_obp = 1; 670 5648 setje rsp->rd_window_base = 0; 671 5648 setje rsp->rd_window_size = size; 672 5648 setje rsp->rd_window_virt = (caddr_t)((ulong_t)addr); 673 0 stevel } 674 0 stevel 675 0 stevel /* 676 0 stevel * Allocate physical memory for non-OBP ramdisks. 677 0 stevel * Create pseudo block and raw device nodes. 678 0 stevel */ 679 0 stevel if (dip == rd_dip) { 680 0 stevel rsp->rd_npages = btopr(size); 681 0 stevel rsp->rd_ppa = rd_phys_alloc(rsp->rd_npages); 682 0 stevel if (rsp->rd_ppa == NULL) { 683 0 stevel goto create_failed; 684 0 stevel } 685 0 stevel 686 0 stevel /* 687 0 stevel * For non-OBP ramdisks the device nodes are: 688 0 stevel * 689 0 stevel * /devices/pseudo/ramdisk@0:<diskname> 690 0 stevel * /devices/pseudo/ramdisk@0:<diskname>,raw 691 0 stevel */ 692 0 stevel (void) snprintf(namebuf, sizeof (namebuf), "%s", 693 0 stevel rsp->rd_name); 694 0 stevel if (ddi_create_minor_node(dip, namebuf, S_IFBLK, minor, 695 0 stevel DDI_PSEUDO, 0) == DDI_FAILURE) { 696 0 stevel goto create_failed; 697 0 stevel } 698 0 stevel (void) snprintf(namebuf, sizeof (namebuf), "%s,raw", 699 0 stevel rsp->rd_name); 700 0 stevel if (ddi_create_minor_node(dip, namebuf, S_IFCHR, minor, 701 0 stevel DDI_PSEUDO, 0) == DDI_FAILURE) { 702 0 stevel goto create_failed; 703 0 stevel } 704 0 stevel } else { 705 0 stevel /* 706 0 stevel * For OBP-created ramdisks the device nodes are: 707 0 stevel * 708 0 stevel * /devices/ramdisk-<diskname>:a 709 0 stevel * /devices/ramdisk-<diskname>:a,raw 710 0 stevel */ 711 0 stevel if (ddi_create_minor_node(dip, "a", S_IFBLK, minor, 712 0 stevel DDI_PSEUDO, 0) == DDI_FAILURE) { 713 0 stevel goto create_failed; 714 0 stevel } 715 0 stevel if (ddi_create_minor_node(dip, "a,raw", S_IFCHR, minor, 716 0 stevel DDI_PSEUDO, 0) == DDI_FAILURE) { 717 0 stevel goto create_failed; 718 0 stevel } 719 0 stevel } 720 0 stevel 721 0 stevel /* 722 0 stevel * Create the "Size" and "Nblocks" properties. 723 0 stevel */ 724 0 stevel fulldev = makedevice(ddi_driver_major(dip), minor); 725 0 stevel Size_prop_val = size; 726 0 stevel if ((ddi_prop_update_int64(fulldev, dip, 727 0 stevel SIZE_PROP_NAME, Size_prop_val)) != DDI_PROP_SUCCESS) { 728 0 stevel goto create_failed; 729 0 stevel } 730 0 stevel Nblocks_prop_val = size / DEV_BSIZE; 731 0 stevel if ((ddi_prop_update_int64(fulldev, dip, 732 0 stevel NBLOCKS_PROP_NAME, Nblocks_prop_val)) != DDI_PROP_SUCCESS) { 733 0 stevel goto create_failed; 734 0 stevel } 735 0 stevel 736 0 stevel /* 737 0 stevel * Allocate kstat stuff. 738 0 stevel */ 739 0 stevel rsp->rd_kstat = kstat_create(RD_DRIVER_NAME, minor, NULL, 740 4363 blakej "disk", KSTAT_TYPE_IO, 1, 0); 741 0 stevel if (rsp->rd_kstat) { 742 0 stevel mutex_init(&rsp->rd_kstat_lock, NULL, 743 0 stevel MUTEX_DRIVER, NULL); 744 0 stevel rsp->rd_kstat->ks_lock = &rsp->rd_kstat_lock; 745 0 stevel kstat_install(rsp->rd_kstat); 746 0 stevel } 747 0 stevel 748 0 stevel rd_fake_disk_geometry(rsp); 749 0 stevel 750 0 stevel return (rsp); 751 0 stevel 752 0 stevel create_failed: 753 0 stevel /* 754 0 stevel * Cleanup. 755 0 stevel */ 756 0 stevel rd_dealloc_resources(rsp); 757 0 stevel 758 0 stevel return (NULL); 759 0 stevel } 760 0 stevel 761 0 stevel /* 762 0 stevel * Undo what we did in rd_attach, freeing resources and removing things which 763 0 stevel * we installed. The system framework guarantees we are not active with this 764 0 stevel * devinfo node in any other entry points at this time. 765 0 stevel */ 766 0 stevel static int 767 0 stevel rd_common_detach(dev_info_t *dip) 768 0 stevel { 769 0 stevel if (dip == rd_dip) { 770 0 stevel /* 771 0 stevel * Pseudo node: can't detach if any pseudo ramdisks exist. 772 0 stevel */ 773 0 stevel if (rd_is_busy()) { 774 0 stevel return (DDI_FAILURE); 775 0 stevel } 776 0 stevel ddi_soft_state_free(rd_statep, RD_CTL_MINOR); 777 0 stevel rd_dip = NULL; 778 0 stevel } else { 779 0 stevel /* 780 0 stevel * A 'real' ramdisk; find the state and free resources. 781 0 stevel */ 782 0 stevel rd_devstate_t *rsp; 783 0 stevel 784 0 stevel if ((rsp = rd_find_dip_state(dip)) != NULL) { 785 0 stevel rd_dealloc_resources(rsp); 786 0 stevel } 787 0 stevel } 788 0 stevel ddi_remove_minor_node(dip, NULL); 789 0 stevel 790 0 stevel return (DDI_SUCCESS); 791 0 stevel } 792 0 stevel 793 0 stevel static int 794 0 stevel rd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 795 0 stevel { 796 0 stevel char *name; 797 0 stevel rd_existing_t *ep = NULL; 798 5648 setje uint_t obpaddr = 0, nep, i; 799 0 stevel size_t size = 0; 800 0 stevel rd_devstate_t *rsp; 801 0 stevel 802 0 stevel switch (cmd) { 803 0 stevel 804 0 stevel case DDI_ATTACH: 805 0 stevel mutex_enter(&rd_lock); 806 0 stevel 807 0 stevel /* 808 0 stevel * For pseudo ramdisk devinfo set up state 0 and :ctl device; 809 0 stevel * else it's an OBP-created ramdisk. 810 0 stevel */ 811 0 stevel if (is_pseudo_device(dip)) { 812 0 stevel rd_dip = dip; 813 0 stevel rd_init_tuneables(); 814 0 stevel 815 0 stevel /* 816 0 stevel * The zeroth minor is reserved for the ramdisk 817 0 stevel * 'control' device. 818 0 stevel */ 819 0 stevel if (ddi_soft_state_zalloc(rd_statep, RD_CTL_MINOR) == 820 0 stevel DDI_FAILURE) { 821 0 stevel goto attach_failed; 822 0 stevel } 823 0 stevel rsp = ddi_get_soft_state(rd_statep, RD_CTL_MINOR); 824 0 stevel rsp->rd_dip = dip; 825 0 stevel 826 0 stevel if (ddi_create_minor_node(dip, RD_CTL_NODE, 827 0 stevel S_IFCHR, 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 828 0 stevel goto attach_failed; 829 0 stevel } 830 0 stevel } else { 831 9956 William #ifdef __sparc 832 9956 William if (bootops_obp_ramdisk_disabled) 833 9956 William goto attach_failed; 834 9956 William #endif /* __sparc */ 835 9956 William 836 0 stevel RD_STRIP_PREFIX(name, ddi_node_name(dip)); 837 0 stevel 838 0 stevel if (strlen(name) > RD_NAME_LEN) { 839 0 stevel cmn_err(CE_CONT, 840 0 stevel "%s: name too long - ignoring\n", name); 841 0 stevel goto attach_failed; 842 0 stevel } 843 0 stevel 844 0 stevel /* 845 0 stevel * An OBP-created ramdisk must have an 'existing' 846 0 stevel * property; get and check it. 847 0 stevel */ 848 0 stevel if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, 849 5648 setje DDI_PROP_DONTPASS, OBP_EXISTING_PROP_NAME, 850 5648 setje (uchar_t **)&ep, &nep) == DDI_SUCCESS) { 851 5648 setje 852 5648 setje if (nep == 0 || (nep % sizeof (*ep)) != 0) { 853 5648 setje cmn_err(CE_CONT, 854 5648 setje "%s: " OBP_EXISTING_PROP_NAME 855 5648 setje " illegal size\n", name); 856 5648 setje goto attach_failed; 857 5648 setje } 858 5648 setje nep /= sizeof (*ep); 859 5648 setje 860 5648 setje /* 861 5648 setje * Calculate the size of the ramdisk. 862 5648 setje */ 863 5648 setje for (i = 0; i < nep; ++i) { 864 5648 setje size += ep[i].size; 865 5648 setje } 866 5648 setje } else if ((obpaddr = ddi_prop_get_int(DDI_DEV_T_ANY, 867 5648 setje dip, DDI_PROP_DONTPASS, OBP_ADDRESS_PROP_NAME, 868 5648 setje 0)) != 0) { 869 5648 setje 870 5648 setje size = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 871 5648 setje DDI_PROP_DONTPASS, OBP_SIZE_PROP_NAME, 0); 872 5648 setje } else { 873 5648 setje cmn_err(CE_CONT, "%s: missing OBP properties\n", 874 5648 setje name); 875 0 stevel goto attach_failed; 876 0 stevel } 877 0 stevel 878 0 stevel /* 879 0 stevel * Allocate driver resources for the ramdisk. 880 0 stevel */ 881 5648 setje if ((rsp = rd_alloc_resources(name, obpaddr, size, 882 0 stevel dip)) == NULL) { 883 0 stevel goto attach_failed; 884 0 stevel } 885 0 stevel 886 0 stevel rsp->rd_existing = ep; 887 0 stevel rsp->rd_nexisting = nep; 888 0 stevel } 889 0 stevel 890 0 stevel mutex_exit(&rd_lock); 891 0 stevel 892 0 stevel ddi_report_dev(dip); 893 0 stevel 894 0 stevel return (DDI_SUCCESS); 895 0 stevel 896 0 stevel case DDI_RESUME: 897 0 stevel return (DDI_SUCCESS); 898 0 stevel 899 0 stevel default: 900 0 stevel return (DDI_FAILURE); 901 0 stevel } 902 0 stevel 903 0 stevel attach_failed: 904 0 stevel /* 905 0 stevel * Use our common detach routine to unallocate any stuff which 906 0 stevel * was allocated above. 907 0 stevel */ 908 0 stevel (void) rd_common_detach(dip); 909 0 stevel mutex_exit(&rd_lock); 910 0 stevel 911 0 stevel if (ep != NULL) { 912 0 stevel ddi_prop_free(ep); 913 0 stevel } 914 0 stevel return (DDI_FAILURE); 915 0 stevel } 916 0 stevel 917 0 stevel static int 918 0 stevel rd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 919 0 stevel { 920 0 stevel int e; 921 0 stevel 922 0 stevel switch (cmd) { 923 0 stevel 924 0 stevel case DDI_DETACH: 925 0 stevel mutex_enter(&rd_lock); 926 0 stevel e = rd_common_detach(dip); 927 0 stevel mutex_exit(&rd_lock); 928 0 stevel 929 0 stevel return (e); 930 0 stevel 931 0 stevel case DDI_SUSPEND: 932 0 stevel return (DDI_SUCCESS); 933 0 stevel 934 0 stevel default: 935 0 stevel return (DDI_FAILURE); 936 0 stevel } 937 0 stevel } 938 0 stevel 939 0 stevel /*ARGSUSED*/ 940 0 stevel static int 941 0 stevel rd_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 942 0 stevel { 943 0 stevel rd_devstate_t *rsp; 944 0 stevel 945 0 stevel switch (infocmd) { 946 0 stevel case DDI_INFO_DEVT2DEVINFO: 947 0 stevel if ((rsp = ddi_get_soft_state(rd_statep, 948 0 stevel getminor((dev_t)arg))) != NULL) { 949 0 stevel *result = rsp->rd_dip; 950 0 stevel return (DDI_SUCCESS); 951 0 stevel } 952 0 stevel *result = NULL; 953 0 stevel return (DDI_FAILURE); 954 0 stevel 955 0 stevel case DDI_INFO_DEVT2INSTANCE: 956 0 stevel if ((rsp = ddi_get_soft_state(rd_statep, 957 0 stevel getminor((dev_t)arg))) != NULL) { 958 0 stevel *result = (void *)(uintptr_t) 959 0 stevel ddi_get_instance(rsp->rd_dip); 960 0 stevel return (DDI_SUCCESS); 961 0 stevel } 962 0 stevel *result = NULL; 963 0 stevel return (DDI_FAILURE); 964 0 stevel 965 0 stevel default: 966 0 stevel return (DDI_FAILURE); 967 0 stevel } 968 0 stevel } 969 0 stevel 970 0 stevel /*ARGSUSED3*/ 971 0 stevel static int 972 0 stevel rd_open(dev_t *devp, int flag, int otyp, cred_t *credp) 973 0 stevel { 974 0 stevel minor_t minor; 975 0 stevel rd_devstate_t *rsp; 976 0 stevel 977 0 stevel mutex_enter(&rd_lock); 978 0 stevel 979 0 stevel minor = getminor(*devp); 980 0 stevel if (minor == RD_CTL_MINOR) { 981 0 stevel /* 982 0 stevel * Master control device; must be opened exclusively. 983 0 stevel */ 984 0 stevel if ((flag & FEXCL) != FEXCL || otyp != OTYP_CHR) { 985 0 stevel mutex_exit(&rd_lock); 986 0 stevel return (EINVAL); 987 0 stevel } 988 0 stevel 989 0 stevel rsp = ddi_get_soft_state(rd_statep, RD_CTL_MINOR); 990 0 stevel if (rsp == NULL) { 991 0 stevel mutex_exit(&rd_lock); 992 0 stevel return (ENXIO); 993 0 stevel } 994 0 stevel 995 0 stevel if (rd_is_open(rsp)) { 996 0 stevel mutex_exit(&rd_lock); 997 0 stevel return (EBUSY); 998 0 stevel } 999 0 stevel (void) rd_opened(rsp, OTYP_CHR); 1000 0 stevel 1001 0 stevel mutex_exit(&rd_lock); 1002 0 stevel 1003 0 stevel return (0); 1004 0 stevel } 1005 0 stevel 1006 0 stevel rsp = ddi_get_soft_state(rd_statep, minor); 1007 0 stevel if (rsp == NULL) { 1008 0 stevel mutex_exit(&rd_lock); 1009 0 stevel return (ENXIO); 1010 0 stevel } 1011 0 stevel 1012 0 stevel if (rd_opened(rsp, otyp) == -1) { 1013 0 stevel mutex_exit(&rd_lock); 1014 0 stevel return (EINVAL); 1015 0 stevel } 1016 0 stevel 1017 0 stevel mutex_exit(&rd_lock); 1018 0 stevel return (0); 1019 0 stevel } 1020 0 stevel 1021 0 stevel /*ARGSUSED*/ 1022 0 stevel static int 1023 0 stevel rd_close(dev_t dev, int flag, int otyp, struct cred *credp) 1024 0 stevel { 1025 0 stevel minor_t minor; 1026 0 stevel rd_devstate_t *rsp; 1027 0 stevel 1028 0 stevel mutex_enter(&rd_lock); 1029 0 stevel 1030 0 stevel minor = getminor(dev); 1031 0 stevel 1032 0 stevel rsp = ddi_get_soft_state(rd_statep, minor); 1033 0 stevel if (rsp == NULL) { 1034 0 stevel mutex_exit(&rd_lock); 1035 0 stevel return (EINVAL); 1036 0 stevel } 1037 0 stevel 1038 0 stevel rd_closed(rsp, otyp); 1039 0 stevel 1040 0 stevel mutex_exit(&rd_lock); 1041 0 stevel 1042 0 stevel return (0); 1043 0 stevel } 1044 0 stevel 1045 0 stevel static void 1046 0 stevel rd_minphys(struct buf *bp) 1047 0 stevel { 1048 0 stevel if (bp->b_bcount > rd_maxphys) { 1049 0 stevel bp->b_bcount = rd_maxphys; 1050 0 stevel } 1051 0 stevel } 1052 0 stevel 1053 0 stevel static void 1054 0 stevel rd_rw(rd_devstate_t *rsp, struct buf *bp, offset_t offset, size_t nbytes) 1055 0 stevel { 1056 0 stevel int reading = bp->b_flags & B_READ; 1057 0 stevel caddr_t buf_addr; 1058 0 stevel 1059 0 stevel bp_mapin(bp); 1060 0 stevel buf_addr = bp->b_un.b_addr; 1061 0 stevel 1062 0 stevel while (nbytes > 0) { 1063 0 stevel offset_t off_in_window; 1064 0 stevel size_t rem_in_window, copy_bytes; 1065 0 stevel caddr_t raddr; 1066 0 stevel 1067 0 stevel mutex_enter(&rsp->rd_device_lock); 1068 0 stevel rd_map_window(rsp, offset); 1069 0 stevel 1070 0 stevel off_in_window = offset - rsp->rd_window_base; 1071 0 stevel rem_in_window = rsp->rd_window_size - off_in_window; 1072 0 stevel 1073 0 stevel raddr = rsp->rd_window_virt + off_in_window; 1074 0 stevel copy_bytes = MIN(nbytes, rem_in_window); 1075 0 stevel 1076 0 stevel if (reading) { 1077 0 stevel (void) bcopy(raddr, buf_addr, copy_bytes); 1078 0 stevel } else { 1079 0 stevel (void) bcopy(buf_addr, raddr, copy_bytes); 1080 0 stevel } 1081 0 stevel mutex_exit(&rsp->rd_device_lock); 1082 0 stevel 1083 0 stevel offset += copy_bytes; 1084 0 stevel buf_addr += copy_bytes; 1085 0 stevel nbytes -= copy_bytes; 1086 0 stevel } 1087 0 stevel } 1088 0 stevel 1089 9956 William /* 1090 9956 William * On Sparc, this function deals with both pseudo ramdisks and OBP ramdisks. 1091 9956 William * In the case where we freed the "bootarchive" ramdisk in bop_free_archive(), 1092 9956 William * we stop allowing access to the OBP ramdisks. To do so, we set the 1093 9956 William * bootops_obp_ramdisk_disabled flag to true, and we check if the operation 1094 9956 William * is for an OBP ramdisk. In this case we indicate an ENXIO error. 1095 9956 William */ 1096 0 stevel static int 1097 0 stevel rd_strategy(struct buf *bp) 1098 0 stevel { 1099 0 stevel rd_devstate_t *rsp; 1100 0 stevel offset_t offset; 1101 0 stevel 1102 0 stevel rsp = ddi_get_soft_state(rd_statep, getminor(bp->b_edev)); 1103 0 stevel offset = bp->b_blkno * DEV_BSIZE; 1104 0 stevel 1105 9956 William #ifdef __sparc 1106 9956 William if (rsp == NULL || 1107 9956 William (bootops_obp_ramdisk_disabled && 1108 9956 William (rsp->rd_dip != rd_dip || rd_dip == NULL))) { /* OBP ramdisk */ 1109 9956 William #else /* __sparc */ 1110 0 stevel if (rsp == NULL) { 1111 9956 William #endif /* __sparc */ 1112 0 stevel bp->b_error = ENXIO; 1113 0 stevel bp->b_flags |= B_ERROR; 1114 0 stevel } else if (offset >= rsp->rd_size) { 1115 0 stevel bp->b_error = EINVAL; 1116 0 stevel bp->b_flags |= B_ERROR; 1117 0 stevel } else { 1118 0 stevel size_t nbytes; 1119 0 stevel 1120 0 stevel if (rsp->rd_kstat) { 1121 0 stevel mutex_enter(rsp->rd_kstat->ks_lock); 1122 0 stevel kstat_runq_enter(KSTAT_IO_PTR(rsp->rd_kstat)); 1123 0 stevel mutex_exit(rsp->rd_kstat->ks_lock); 1124 0 stevel } 1125 0 stevel 1126 0 stevel nbytes = min(bp->b_bcount, rsp->rd_size - offset); 1127 0 stevel 1128 0 stevel rd_rw(rsp, bp, offset, nbytes); 1129 0 stevel 1130 0 stevel bp->b_resid = bp->b_bcount - nbytes; 1131 0 stevel 1132 0 stevel if (rsp->rd_kstat) { 1133 0 stevel kstat_io_t *kioptr; 1134 0 stevel 1135 0 stevel mutex_enter(rsp->rd_kstat->ks_lock); 1136 0 stevel kioptr = KSTAT_IO_PTR(rsp->rd_kstat); 1137 0 stevel if (bp->b_flags & B_READ) { 1138 0 stevel kioptr->nread += nbytes; 1139 0 stevel kioptr->reads++; 1140 0 stevel } else { 1141 0 stevel kioptr->nwritten += nbytes; 1142 0 stevel kioptr->writes++; 1143 0 stevel } 1144 0 stevel kstat_runq_exit(kioptr); 1145 0 stevel mutex_exit(rsp->rd_kstat->ks_lock); 1146 0 stevel } 1147 0 stevel } 1148 0 stevel 1149 0 stevel biodone(bp); 1150 0 stevel return (0); 1151 0 stevel } 1152 0 stevel 1153 0 stevel /*ARGSUSED*/ 1154 0 stevel static int 1155 0 stevel rd_read(dev_t dev, struct uio *uiop, cred_t *credp) 1156 0 stevel { 1157 0 stevel rd_devstate_t *rsp; 1158 0 stevel 1159 0 stevel rsp = ddi_get_soft_state(rd_statep, getminor(dev)); 1160 0 stevel 1161 0 stevel if (uiop->uio_offset >= rsp->rd_size) 1162 0 stevel return (EINVAL); 1163 0 stevel 1164 0 stevel return (physio(rd_strategy, NULL, dev, B_READ, rd_minphys, uiop)); 1165 0 stevel } 1166 0 stevel 1167 0 stevel /*ARGSUSED*/ 1168 0 stevel static int 1169 0 stevel rd_write(dev_t dev, register struct uio *uiop, cred_t *credp) 1170 0 stevel { 1171 0 stevel rd_devstate_t *rsp; 1172 0 stevel 1173 0 stevel rsp = ddi_get_soft_state(rd_statep, getminor(dev)); 1174 0 stevel 1175 0 stevel if (uiop->uio_offset >= rsp->rd_size) 1176 0 stevel return (EINVAL); 1177 0 stevel 1178 0 stevel return (physio(rd_strategy, NULL, dev, B_WRITE, rd_minphys, uiop)); 1179 0 stevel } 1180 0 stevel 1181 0 stevel /*ARGSUSED*/ 1182 0 stevel static int 1183 0 stevel rd_create_disk(dev_t dev, struct rd_ioctl *urip, int mode, int *rvalp) 1184 0 stevel { 1185 0 stevel struct rd_ioctl kri; 1186 0 stevel size_t size; 1187 0 stevel rd_devstate_t *rsp; 1188 0 stevel 1189 0 stevel if (ddi_copyin(urip, &kri, sizeof (kri), mode) == -1) { 1190 0 stevel return (EFAULT); 1191 0 stevel } 1192 0 stevel 1193 0 stevel kri.ri_name[RD_NAME_LEN] = '\0'; 1194 0 stevel 1195 0 stevel size = kri.ri_size; 1196 0 stevel if (size == 0) { 1197 0 stevel return (EINVAL); 1198 0 stevel } 1199 0 stevel size = ptob(btopr(size)); 1200 0 stevel 1201 0 stevel mutex_enter(&rd_lock); 1202 0 stevel 1203 0 stevel if (rd_find_named_disk(kri.ri_name) != NULL) { 1204 0 stevel mutex_exit(&rd_lock); 1205 0 stevel return (EEXIST); 1206 0 stevel } 1207 0 stevel 1208 5648 setje rsp = rd_alloc_resources(kri.ri_name, 0, size, rd_dip); 1209 0 stevel if (rsp == NULL) { 1210 0 stevel mutex_exit(&rd_lock); 1211 0 stevel return (EAGAIN); 1212 0 stevel } 1213 0 stevel 1214 0 stevel mutex_exit(&rd_lock); 1215 0 stevel 1216 0 stevel return (ddi_copyout(&kri, urip, sizeof (kri), mode) == -1 ? EFAULT : 0); 1217 0 stevel } 1218 0 stevel 1219 0 stevel /*ARGSUSED*/ 1220 0 stevel static int 1221 0 stevel rd_delete_disk(dev_t dev, struct rd_ioctl *urip, int mode) 1222 0 stevel { 1223 0 stevel struct rd_ioctl kri; 1224 0 stevel rd_devstate_t *rsp; 1225 0 stevel 1226 0 stevel if (ddi_copyin(urip, &kri, sizeof (kri), mode) == -1) { 1227 0 stevel return (EFAULT); 1228 0 stevel } 1229 0 stevel 1230 0 stevel kri.ri_name[RD_NAME_LEN] = '\0'; 1231 0 stevel 1232 0 stevel mutex_enter(&rd_lock); 1233 0 stevel 1234 0 stevel rsp = rd_find_named_disk(kri.ri_name); 1235 0 stevel if (rsp == NULL || rsp->rd_dip != rd_dip) { 1236 0 stevel mutex_exit(&rd_lock); 1237 0 stevel return (EINVAL); 1238 0 stevel } 1239 0 stevel if (rd_is_open(rsp)) { 1240 0 stevel mutex_exit(&rd_lock); 1241 0 stevel return (EBUSY); 1242 0 stevel } 1243 0 stevel 1244 0 stevel rd_dealloc_resources(rsp); 1245 0 stevel 1246 0 stevel mutex_exit(&rd_lock); 1247 0 stevel 1248 0 stevel return (0); 1249 0 stevel } 1250 0 stevel 1251 0 stevel /*ARGSUSED*/ 1252 0 stevel static int 1253 0 stevel rd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 1254 0 stevel { 1255 0 stevel minor_t minor; 1256 0 stevel int error; 1257 0 stevel enum dkio_state dkstate; 1258 0 stevel rd_devstate_t *rsp; 1259 0 stevel 1260 0 stevel minor = getminor(dev); 1261 0 stevel 1262 0 stevel /* 1263 0 stevel * Ramdisk ioctls only apply to the master device. 1264 0 stevel */ 1265 0 stevel if (minor == RD_CTL_MINOR) { 1266 0 stevel struct rd_ioctl *rip = (struct rd_ioctl *)arg; 1267 0 stevel 1268 0 stevel /* 1269 0 stevel * The query commands only need read-access - i.e., normal 1270 0 stevel * users are allowed to do those on the controlling device 1271 0 stevel * as long as they can open it read-only. 1272 0 stevel */ 1273 0 stevel switch (cmd) { 1274 0 stevel case RD_CREATE_DISK: 1275 0 stevel if ((mode & FWRITE) == 0) 1276 0 stevel return (EPERM); 1277 0 stevel return (rd_create_disk(dev, rip, mode, rvalp)); 1278 0 stevel 1279 0 stevel case RD_DELETE_DISK: 1280 0 stevel if ((mode & FWRITE) == 0) 1281 0 stevel return (EPERM); 1282 0 stevel return (rd_delete_disk(dev, rip, mode)); 1283 0 stevel 1284 0 stevel default: 1285 0 stevel return (EINVAL); 1286 0 stevel } 1287 0 stevel } 1288 0 stevel 1289 0 stevel rsp = ddi_get_soft_state(rd_statep, minor); 1290 0 stevel if (rsp == NULL) { 1291 0 stevel return (ENXIO); 1292 0 stevel } 1293 0 stevel 1294 0 stevel /* 1295 0 stevel * These are for faking out utilities like newfs. 1296 0 stevel */ 1297 0 stevel switch (cmd) { 1298 0 stevel case DKIOCGVTOC: 1299 0 stevel switch (ddi_model_convert_from(mode & FMODELS)) { 1300 0 stevel case DDI_MODEL_ILP32: { 1301 0 stevel struct vtoc32 vtoc32; 1302 0 stevel 1303 0 stevel vtoctovtoc32(rsp->rd_vtoc, vtoc32); 1304 0 stevel if (ddi_copyout(&vtoc32, (void *)arg, 1305 0 stevel sizeof (struct vtoc32), mode)) 1306 0 stevel return (EFAULT); 1307 0 stevel } 1308 0 stevel break; 1309 0 stevel 1310 0 stevel case DDI_MODEL_NONE: 1311 0 stevel if (ddi_copyout(&rsp->rd_vtoc, (void *)arg, 1312 0 stevel sizeof (struct vtoc), mode)) 1313 0 stevel return (EFAULT); 1314 0 stevel break; 1315 0 stevel } 1316 0 stevel return (0); 1317 0 stevel case DKIOCINFO: 1318 0 stevel error = ddi_copyout(&rsp->rd_ci, (void *)arg, 1319 0 stevel sizeof (struct dk_cinfo), mode); 1320 0 stevel if (error) 1321 0 stevel return (EFAULT); 1322 0 stevel return (0); 1323 0 stevel case DKIOCG_VIRTGEOM: 1324 0 stevel case DKIOCG_PHYGEOM: 1325 0 stevel case DKIOCGGEOM: 1326 0 stevel error = ddi_copyout(&rsp->rd_dkg, (void *)arg, 1327 0 stevel sizeof (struct dk_geom), mode); 1328 0 stevel if (error) 1329 0 stevel return (EFAULT); 1330 0 stevel return (0); 1331 0 stevel case DKIOCSTATE: 1332 0 stevel /* the file is always there */ 1333 0 stevel dkstate = DKIO_INSERTED; 1334 0 stevel error = ddi_copyout(&dkstate, (void *)arg, 1335 0 stevel sizeof (enum dkio_state), mode); 1336 0 stevel if (error) 1337 0 stevel return (EFAULT); 1338 0 stevel return (0); 1339 0 stevel default: 1340 0 stevel return (ENOTTY); 1341 0 stevel } 1342 0 stevel } 1343 0 stevel 1344 0 stevel 1345 0 stevel static struct cb_ops rd_cb_ops = { 1346 0 stevel rd_open, 1347 0 stevel rd_close, 1348 0 stevel rd_strategy, 1349 0 stevel nodev, 1350 0 stevel nodev, /* dump */ 1351 0 stevel rd_read, 1352 0 stevel rd_write, 1353 0 stevel rd_ioctl, 1354 0 stevel nodev, /* devmap */ 1355 0 stevel nodev, /* mmap */ 1356 0 stevel nodev, /* segmap */ 1357 0 stevel nochpoll, /* poll */ 1358 0 stevel ddi_prop_op, 1359 0 stevel NULL, 1360 0 stevel D_NEW | D_MP 1361 0 stevel }; 1362 0 stevel 1363 0 stevel static struct dev_ops rd_ops = { 1364 0 stevel DEVO_REV, 1365 0 stevel 0, 1366 0 stevel rd_getinfo, 1367 0 stevel nulldev, /* identify */ 1368 0 stevel nulldev, /* probe */ 1369 0 stevel rd_attach, 1370 0 stevel rd_detach, 1371 0 stevel nodev, /* reset */ 1372 0 stevel &rd_cb_ops, 1373 7656 Sherry (struct bus_ops *)0, 1374 7656 Sherry NULL, 1375 7656 Sherry ddi_quiesce_not_needed, /* quiesce */ 1376 0 stevel }; 1377 0 stevel 1378 0 stevel 1379 0 stevel extern struct mod_ops mod_driverops; 1380 0 stevel 1381 0 stevel static struct modldrv modldrv = { 1382 0 stevel &mod_driverops, 1383 5648 setje "ramdisk driver", 1384 0 stevel &rd_ops 1385 0 stevel }; 1386 0 stevel 1387 0 stevel static struct modlinkage modlinkage = { 1388 0 stevel MODREV_1, 1389 0 stevel &modldrv, 1390 0 stevel 0 1391 0 stevel }; 1392 0 stevel 1393 0 stevel int 1394 0 stevel _init(void) 1395 0 stevel { 1396 0 stevel int e; 1397 0 stevel 1398 0 stevel if ((e = ddi_soft_state_init(&rd_statep, 1399 0 stevel sizeof (rd_devstate_t), 0)) != 0) { 1400 0 stevel return (e); 1401 0 stevel } 1402 0 stevel 1403 0 stevel mutex_init(&rd_lock, NULL, MUTEX_DRIVER, NULL); 1404 0 stevel 1405 0 stevel if ((e = mod_install(&modlinkage)) != 0) { 1406 0 stevel mutex_destroy(&rd_lock); 1407 0 stevel ddi_soft_state_fini(&rd_statep); 1408 0 stevel } 1409 0 stevel 1410 0 stevel return (e); 1411 0 stevel } 1412 0 stevel 1413 0 stevel int 1414 0 stevel _fini(void) 1415 0 stevel { 1416 0 stevel int e; 1417 0 stevel 1418 0 stevel if ((e = mod_remove(&modlinkage)) != 0) { 1419 0 stevel return (e); 1420 0 stevel } 1421 0 stevel 1422 0 stevel ddi_soft_state_fini(&rd_statep); 1423 0 stevel mutex_destroy(&rd_lock); 1424 0 stevel 1425 0 stevel return (e); 1426 0 stevel } 1427 0 stevel 1428 0 stevel int 1429 0 stevel _info(struct modinfo *modinfop) 1430 0 stevel { 1431 0 stevel return (mod_info(&modlinkage, modinfop)); 1432 0 stevel } 1433