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