1 | /* $NetBSD: device-mapper.c,v 1.38 2016/07/11 11:31:50 msaitoh Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2010 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Adam Hamsik. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * I want to say thank you to all people who helped me with this project. |
34 | */ |
35 | |
36 | #include <sys/types.h> |
37 | #include <sys/param.h> |
38 | |
39 | #include <sys/buf.h> |
40 | #include <sys/conf.h> |
41 | #include <sys/device.h> |
42 | #include <sys/dkio.h> |
43 | #include <sys/disk.h> |
44 | #include <sys/disklabel.h> |
45 | #include <sys/ioctl.h> |
46 | #include <sys/ioccom.h> |
47 | #include <sys/kmem.h> |
48 | #include <sys/kauth.h> |
49 | |
50 | #include "netbsd-dm.h" |
51 | #include "dm.h" |
52 | #include "ioconf.h" |
53 | |
54 | static dev_type_open(dmopen); |
55 | static dev_type_close(dmclose); |
56 | static dev_type_read(dmread); |
57 | static dev_type_write(dmwrite); |
58 | static dev_type_ioctl(dmioctl); |
59 | static dev_type_strategy(dmstrategy); |
60 | static dev_type_size(dmsize); |
61 | |
62 | /* attach and detach routines */ |
63 | #ifdef _MODULE |
64 | static int dmdestroy(void); |
65 | #endif |
66 | |
67 | static void dm_doinit(void); |
68 | |
69 | static int dm_cmd_to_fun(prop_dictionary_t); |
70 | static int disk_ioctl_switch(dev_t, u_long, void *); |
71 | static int dm_ioctl_switch(u_long); |
72 | static void dmminphys(struct buf *); |
73 | |
74 | /* CF attach/detach functions used for power management */ |
75 | static int dm_detach(device_t, int); |
76 | static void dm_attach(device_t, device_t, void *); |
77 | static int dm_match(device_t, cfdata_t, void *); |
78 | |
79 | /* ***Variable-definitions*** */ |
80 | const struct bdevsw dm_bdevsw = { |
81 | .d_open = dmopen, |
82 | .d_close = dmclose, |
83 | .d_strategy = dmstrategy, |
84 | .d_ioctl = dmioctl, |
85 | .d_dump = nodump, |
86 | .d_psize = dmsize, |
87 | .d_discard = nodiscard, |
88 | .d_flag = D_DISK | D_MPSAFE |
89 | }; |
90 | |
91 | const struct cdevsw dm_cdevsw = { |
92 | .d_open = dmopen, |
93 | .d_close = dmclose, |
94 | .d_read = dmread, |
95 | .d_write = dmwrite, |
96 | .d_ioctl = dmioctl, |
97 | .d_stop = nostop, |
98 | .d_tty = notty, |
99 | .d_poll = nopoll, |
100 | .d_mmap = nommap, |
101 | .d_kqfilter = nokqfilter, |
102 | .d_discard = nodiscard, |
103 | .d_flag = D_DISK | D_MPSAFE |
104 | }; |
105 | |
106 | const struct dkdriver dmdkdriver = { |
107 | .d_strategy = dmstrategy |
108 | }; |
109 | |
110 | CFATTACH_DECL3_NEW(dm, 0, |
111 | dm_match, dm_attach, dm_detach, NULL, NULL, NULL, |
112 | DVF_DETACH_SHUTDOWN); |
113 | |
114 | extern struct cfdriver dm_cd; |
115 | |
116 | extern uint32_t dm_dev_counter; |
117 | |
118 | /* |
119 | * This array is used to translate cmd to function pointer. |
120 | * |
121 | * Interface between libdevmapper and lvm2tools uses different |
122 | * names for one IOCTL call because libdevmapper do another thing |
123 | * then. When I run "info" or "mknodes" libdevmapper will send same |
124 | * ioctl to kernel but will do another things in userspace. |
125 | * |
126 | */ |
127 | static const struct cmd_function cmd_fn[] = { |
128 | { .cmd = "version" , .fn = dm_get_version_ioctl, .allowed = 1 }, |
129 | { .cmd = "targets" , .fn = dm_list_versions_ioctl, .allowed = 1 }, |
130 | { .cmd = "create" , .fn = dm_dev_create_ioctl, .allowed = 0 }, |
131 | { .cmd = "info" , .fn = dm_dev_status_ioctl, .allowed = 1 }, |
132 | { .cmd = "mknodes" , .fn = dm_dev_status_ioctl, .allowed = 1 }, |
133 | { .cmd = "names" , .fn = dm_dev_list_ioctl, .allowed = 1 }, |
134 | { .cmd = "suspend" , .fn = dm_dev_suspend_ioctl, .allowed = 0 }, |
135 | { .cmd = "remove" , .fn = dm_dev_remove_ioctl, .allowed = 0 }, |
136 | { .cmd = "rename" , .fn = dm_dev_rename_ioctl, .allowed = 0 }, |
137 | { .cmd = "resume" , .fn = dm_dev_resume_ioctl, .allowed = 0 }, |
138 | { .cmd = "clear" , .fn = dm_table_clear_ioctl, .allowed = 0 }, |
139 | { .cmd = "deps" , .fn = dm_table_deps_ioctl, .allowed = 1 }, |
140 | { .cmd = "reload" , .fn = dm_table_load_ioctl, .allowed = 0 }, |
141 | { .cmd = "status" , .fn = dm_table_status_ioctl, .allowed = 1 }, |
142 | { .cmd = "table" , .fn = dm_table_status_ioctl, .allowed = 1 }, |
143 | { .cmd = NULL, .fn = NULL, .allowed = 0 } |
144 | }; |
145 | |
146 | #ifdef _MODULE |
147 | #include <sys/module.h> |
148 | |
149 | /* Autoconf defines */ |
150 | CFDRIVER_DECL(dm, DV_DISK, NULL); |
151 | |
152 | MODULE(MODULE_CLASS_DRIVER, dm, "dk_subr" ); |
153 | |
154 | /* New module handle routine */ |
155 | static int |
156 | dm_modcmd(modcmd_t cmd, void *arg) |
157 | { |
158 | #ifdef _MODULE |
159 | int error; |
160 | devmajor_t bmajor, cmajor; |
161 | |
162 | error = 0; |
163 | bmajor = -1; |
164 | cmajor = -1; |
165 | |
166 | switch (cmd) { |
167 | case MODULE_CMD_INIT: |
168 | error = config_cfdriver_attach(&dm_cd); |
169 | if (error) |
170 | break; |
171 | |
172 | error = config_cfattach_attach(dm_cd.cd_name, &dm_ca); |
173 | if (error) { |
174 | aprint_error("%s: unable to register cfattach\n" , |
175 | dm_cd.cd_name); |
176 | return error; |
177 | } |
178 | |
179 | error = devsw_attach(dm_cd.cd_name, &dm_bdevsw, &bmajor, |
180 | &dm_cdevsw, &cmajor); |
181 | if (error == EEXIST) |
182 | error = 0; |
183 | if (error) { |
184 | config_cfattach_detach(dm_cd.cd_name, &dm_ca); |
185 | config_cfdriver_detach(&dm_cd); |
186 | break; |
187 | } |
188 | |
189 | dm_doinit(); |
190 | |
191 | break; |
192 | |
193 | case MODULE_CMD_FINI: |
194 | /* |
195 | * Disable unloading of dm module if there are any devices |
196 | * defined in driver. This is probably too strong we need |
197 | * to disable auto-unload only if there is mounted dm device |
198 | * present. |
199 | */ |
200 | if (dm_dev_counter > 0) |
201 | return EBUSY; |
202 | |
203 | error = dmdestroy(); |
204 | if (error) |
205 | break; |
206 | |
207 | config_cfdriver_detach(&dm_cd); |
208 | |
209 | devsw_detach(&dm_bdevsw, &dm_cdevsw); |
210 | break; |
211 | case MODULE_CMD_STAT: |
212 | return ENOTTY; |
213 | |
214 | default: |
215 | return ENOTTY; |
216 | } |
217 | |
218 | return error; |
219 | #else |
220 | return ENOTTY; |
221 | #endif |
222 | } |
223 | #endif /* _MODULE */ |
224 | |
225 | /* |
226 | * dm_match: |
227 | * |
228 | * Autoconfiguration match function for pseudo-device glue. |
229 | */ |
230 | static int |
231 | dm_match(device_t parent, cfdata_t match, void *aux) |
232 | { |
233 | |
234 | /* Pseudo-device; always present. */ |
235 | return (1); |
236 | } |
237 | |
238 | /* |
239 | * dm_attach: |
240 | * |
241 | * Autoconfiguration attach function for pseudo-device glue. |
242 | */ |
243 | static void |
244 | dm_attach(device_t parent, device_t self, void *aux) |
245 | { |
246 | return; |
247 | } |
248 | |
249 | |
250 | /* |
251 | * dm_detach: |
252 | * |
253 | * Autoconfiguration detach function for pseudo-device glue. |
254 | * This routine is called by dm_ioctl::dm_dev_remove_ioctl and by autoconf to |
255 | * remove devices created in device-mapper. |
256 | */ |
257 | static int |
258 | dm_detach(device_t self, int flags) |
259 | { |
260 | dm_dev_t *dmv; |
261 | |
262 | /* Detach device from global device list */ |
263 | if ((dmv = dm_dev_detach(self)) == NULL) |
264 | return ENOENT; |
265 | |
266 | /* Destroy active table first. */ |
267 | dm_table_destroy(&dmv->table_head, DM_TABLE_ACTIVE); |
268 | |
269 | /* Destroy inactive table if exits, too. */ |
270 | dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); |
271 | |
272 | dm_table_head_destroy(&dmv->table_head); |
273 | |
274 | /* Destroy disk device structure */ |
275 | disk_detach(dmv->diskp); |
276 | disk_destroy(dmv->diskp); |
277 | |
278 | /* Destroy device */ |
279 | (void)dm_dev_free(dmv); |
280 | |
281 | /* Decrement device counter After removing device */ |
282 | atomic_dec_32(&dm_dev_counter); |
283 | |
284 | return 0; |
285 | } |
286 | |
287 | static void |
288 | dm_doinit(void) |
289 | { |
290 | dm_target_init(); |
291 | dm_dev_init(); |
292 | dm_pdev_init(); |
293 | } |
294 | |
295 | /* attach routine */ |
296 | void |
297 | dmattach(int n) |
298 | { |
299 | int error; |
300 | |
301 | error = config_cfattach_attach(dm_cd.cd_name, &dm_ca); |
302 | if (error) { |
303 | aprint_error("%s: unable to register cfattach\n" , |
304 | dm_cd.cd_name); |
305 | } else { |
306 | dm_doinit(); |
307 | } |
308 | } |
309 | |
310 | #ifdef _MODULE |
311 | /* Destroy routine */ |
312 | static int |
313 | dmdestroy(void) |
314 | { |
315 | int error; |
316 | |
317 | error = config_cfattach_detach(dm_cd.cd_name, &dm_ca); |
318 | if (error) |
319 | return error; |
320 | |
321 | dm_dev_destroy(); |
322 | dm_pdev_destroy(); |
323 | dm_target_destroy(); |
324 | |
325 | return 0; |
326 | } |
327 | #endif /* _MODULE */ |
328 | |
329 | static int |
330 | dmopen(dev_t dev, int flags, int mode, struct lwp *l) |
331 | { |
332 | |
333 | aprint_debug("dm open routine called %" PRIu32 "\n" , minor(dev)); |
334 | return 0; |
335 | } |
336 | |
337 | static int |
338 | dmclose(dev_t dev, int flags, int mode, struct lwp *l) |
339 | { |
340 | |
341 | aprint_debug("dm close routine called %" PRIu32 "\n" , minor(dev)); |
342 | return 0; |
343 | } |
344 | |
345 | |
346 | static int |
347 | dmioctl(dev_t dev, const u_long cmd, void *data, int flag, struct lwp *l) |
348 | { |
349 | int r; |
350 | prop_dictionary_t dm_dict_in; |
351 | |
352 | r = 0; |
353 | |
354 | aprint_debug("dmioctl called\n" ); |
355 | KASSERT(data != NULL); |
356 | |
357 | if (( r = disk_ioctl_switch(dev, cmd, data)) == ENOTTY) { |
358 | struct plistref *pref = (struct plistref *) data; |
359 | |
360 | /* Check if we were called with NETBSD_DM_IOCTL ioctl |
361 | otherwise quit. */ |
362 | if ((r = dm_ioctl_switch(cmd)) != 0) |
363 | return r; |
364 | |
365 | if((r = prop_dictionary_copyin_ioctl(pref, cmd, &dm_dict_in)) |
366 | != 0) |
367 | return r; |
368 | |
369 | if ((r = dm_check_version(dm_dict_in)) != 0) |
370 | goto cleanup_exit; |
371 | |
372 | /* run ioctl routine */ |
373 | if ((r = dm_cmd_to_fun(dm_dict_in)) != 0) |
374 | goto cleanup_exit; |
375 | |
376 | cleanup_exit: |
377 | r = prop_dictionary_copyout_ioctl(pref, cmd, dm_dict_in); |
378 | prop_object_release(dm_dict_in); |
379 | } |
380 | |
381 | return r; |
382 | } |
383 | |
384 | /* |
385 | * Translate command sent from libdevmapper to func. |
386 | */ |
387 | static int |
388 | dm_cmd_to_fun(prop_dictionary_t dm_dict) |
389 | { |
390 | int i, r; |
391 | prop_string_t command; |
392 | |
393 | r = 0; |
394 | |
395 | if ((command = prop_dictionary_get(dm_dict, DM_IOCTL_COMMAND)) == NULL) |
396 | return EINVAL; |
397 | |
398 | for(i = 0; cmd_fn[i].cmd != NULL; i++) |
399 | if (prop_string_equals_cstring(command, cmd_fn[i].cmd)) |
400 | break; |
401 | |
402 | if (!cmd_fn[i].allowed && |
403 | (r = kauth_authorize_system(kauth_cred_get(), |
404 | KAUTH_SYSTEM_DEVMAPPER, 0, NULL, NULL, NULL)) != 0) |
405 | return r; |
406 | |
407 | if (cmd_fn[i].cmd == NULL) |
408 | return EINVAL; |
409 | |
410 | aprint_debug("ioctl %s called\n" , cmd_fn[i].cmd); |
411 | r = cmd_fn[i].fn(dm_dict); |
412 | |
413 | return r; |
414 | } |
415 | |
416 | /* Call apropriate ioctl handler function. */ |
417 | static int |
418 | dm_ioctl_switch(u_long cmd) |
419 | { |
420 | |
421 | switch(cmd) { |
422 | |
423 | case NETBSD_DM_IOCTL: |
424 | aprint_debug("dm NetBSD_DM_IOCTL called\n" ); |
425 | break; |
426 | default: |
427 | aprint_debug("dm unknown ioctl called\n" ); |
428 | return ENOTTY; |
429 | break; /* NOT REACHED */ |
430 | } |
431 | |
432 | return 0; |
433 | } |
434 | |
435 | /* |
436 | * Check for disk specific ioctls. |
437 | */ |
438 | |
439 | static int |
440 | disk_ioctl_switch(dev_t dev, u_long cmd, void *data) |
441 | { |
442 | dm_dev_t *dmv; |
443 | |
444 | /* disk ioctls make sense only on block devices */ |
445 | if (minor(dev) == 0) |
446 | return ENOTTY; |
447 | |
448 | switch(cmd) { |
449 | case DIOCGWEDGEINFO: |
450 | { |
451 | struct dkwedge_info *dkw = (void *) data; |
452 | unsigned secsize; |
453 | |
454 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) |
455 | return ENODEV; |
456 | |
457 | aprint_debug("DIOCGWEDGEINFO ioctl called\n" ); |
458 | |
459 | strlcpy(dkw->dkw_devname, dmv->name, 16); |
460 | strlcpy(dkw->dkw_wname, dmv->name, DM_NAME_LEN); |
461 | strlcpy(dkw->dkw_parent, dmv->name, 16); |
462 | |
463 | dkw->dkw_offset = 0; |
464 | dm_table_disksize(&dmv->table_head, &dkw->dkw_size, &secsize); |
465 | strcpy(dkw->dkw_ptype, DKW_PTYPE_FFS); |
466 | |
467 | dm_dev_unbusy(dmv); |
468 | break; |
469 | } |
470 | |
471 | case DIOCGDISKINFO: |
472 | { |
473 | struct plistref *pref = (struct plistref *) data; |
474 | |
475 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) |
476 | return ENODEV; |
477 | |
478 | if (dmv->diskp->dk_info == NULL) { |
479 | dm_dev_unbusy(dmv); |
480 | return ENOTSUP; |
481 | } else |
482 | prop_dictionary_copyout_ioctl(pref, cmd, |
483 | dmv->diskp->dk_info); |
484 | |
485 | dm_dev_unbusy(dmv); |
486 | break; |
487 | } |
488 | |
489 | case DIOCCACHESYNC: |
490 | { |
491 | dm_table_entry_t *table_en; |
492 | dm_table_t *tbl; |
493 | |
494 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) |
495 | return ENODEV; |
496 | |
497 | /* Select active table */ |
498 | tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE); |
499 | |
500 | /* |
501 | * Call sync target routine for all table entries. Target sync |
502 | * routine basically call DIOCCACHESYNC on underlying devices. |
503 | */ |
504 | SLIST_FOREACH(table_en, tbl, next) |
505 | { |
506 | (void)table_en->target->sync(table_en); |
507 | } |
508 | dm_table_release(&dmv->table_head, DM_TABLE_ACTIVE); |
509 | dm_dev_unbusy(dmv); |
510 | break; |
511 | } |
512 | |
513 | |
514 | default: |
515 | aprint_debug("unknown disk_ioctl called\n" ); |
516 | return ENOTTY; |
517 | break; /* NOT REACHED */ |
518 | } |
519 | |
520 | return 0; |
521 | } |
522 | |
523 | /* |
524 | * Do all IO operations on dm logical devices. |
525 | */ |
526 | static void |
527 | dmstrategy(struct buf *bp) |
528 | { |
529 | dm_dev_t *dmv; |
530 | dm_table_t *tbl; |
531 | dm_table_entry_t *table_en; |
532 | struct buf *nestbuf; |
533 | |
534 | uint64_t buf_start, buf_len, issued_len; |
535 | uint64_t table_start, table_end; |
536 | uint64_t start, end; |
537 | |
538 | buf_start = bp->b_blkno * DEV_BSIZE; |
539 | buf_len = bp->b_bcount; |
540 | |
541 | tbl = NULL; |
542 | |
543 | table_end = 0; |
544 | issued_len = 0; |
545 | |
546 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(bp->b_dev))) == NULL) { |
547 | bp->b_error = EIO; |
548 | bp->b_resid = bp->b_bcount; |
549 | biodone(bp); |
550 | return; |
551 | } |
552 | |
553 | if (bounds_check_with_mediasize(bp, DEV_BSIZE, |
554 | dm_table_size(&dmv->table_head)) <= 0) { |
555 | dm_dev_unbusy(dmv); |
556 | bp->b_resid = bp->b_bcount; |
557 | biodone(bp); |
558 | return; |
559 | } |
560 | |
561 | /* |
562 | * disk(9) is part of device structure and it can't be used without |
563 | * mutual exclusion, use diskp_mtx until it will be fixed. |
564 | */ |
565 | mutex_enter(&dmv->diskp_mtx); |
566 | disk_busy(dmv->diskp); |
567 | mutex_exit(&dmv->diskp_mtx); |
568 | |
569 | /* Select active table */ |
570 | tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE); |
571 | |
572 | /* Nested buffers count down to zero therefore I have |
573 | to set bp->b_resid to maximal value. */ |
574 | bp->b_resid = bp->b_bcount; |
575 | |
576 | /* |
577 | * Find out what tables I want to select. |
578 | */ |
579 | SLIST_FOREACH(table_en, tbl, next) |
580 | { |
581 | /* I need need number of bytes not blocks. */ |
582 | table_start = table_en->start * DEV_BSIZE; |
583 | /* |
584 | * I have to sub 1 from table_en->length to prevent |
585 | * off by one error |
586 | */ |
587 | table_end = table_start + (table_en->length)* DEV_BSIZE; |
588 | |
589 | start = MAX(table_start, buf_start); |
590 | |
591 | end = MIN(table_end, buf_start + buf_len); |
592 | |
593 | aprint_debug("----------------------------------------\n" ); |
594 | aprint_debug("table_start %010" PRIu64", table_end %010" |
595 | PRIu64 "\n" , table_start, table_end); |
596 | aprint_debug("buf_start %010" PRIu64", buf_len %010" |
597 | PRIu64"\n" , buf_start, buf_len); |
598 | aprint_debug("start-buf_start %010" PRIu64", end %010" |
599 | PRIu64"\n" , start - buf_start, end); |
600 | aprint_debug("start %010" PRIu64" , end %010" |
601 | PRIu64"\n" , start, end); |
602 | aprint_debug("\n----------------------------------------\n" ); |
603 | |
604 | if (start < end) { |
605 | /* create nested buffer */ |
606 | nestbuf = getiobuf(NULL, true); |
607 | |
608 | nestiobuf_setup(bp, nestbuf, start - buf_start, |
609 | (end - start)); |
610 | |
611 | issued_len += end - start; |
612 | |
613 | /* I need number of blocks. */ |
614 | nestbuf->b_blkno = (start - table_start) / DEV_BSIZE; |
615 | |
616 | table_en->target->strategy(table_en, nestbuf); |
617 | } |
618 | } |
619 | |
620 | if (issued_len < buf_len) |
621 | nestiobuf_done(bp, buf_len - issued_len, EINVAL); |
622 | |
623 | mutex_enter(&dmv->diskp_mtx); |
624 | disk_unbusy(dmv->diskp, buf_len, bp != NULL ? bp->b_flags & B_READ : 0); |
625 | mutex_exit(&dmv->diskp_mtx); |
626 | |
627 | dm_table_release(&dmv->table_head, DM_TABLE_ACTIVE); |
628 | dm_dev_unbusy(dmv); |
629 | |
630 | return; |
631 | } |
632 | |
633 | |
634 | static int |
635 | dmread(dev_t dev, struct uio *uio, int flag) |
636 | { |
637 | |
638 | return (physio(dmstrategy, NULL, dev, B_READ, dmminphys, uio)); |
639 | } |
640 | |
641 | static int |
642 | dmwrite(dev_t dev, struct uio *uio, int flag) |
643 | { |
644 | |
645 | return (physio(dmstrategy, NULL, dev, B_WRITE, dmminphys, uio)); |
646 | } |
647 | |
648 | static int |
649 | dmsize(dev_t dev) |
650 | { |
651 | dm_dev_t *dmv; |
652 | uint64_t size; |
653 | |
654 | size = 0; |
655 | |
656 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) |
657 | return -ENOENT; |
658 | |
659 | size = dm_table_size(&dmv->table_head); |
660 | dm_dev_unbusy(dmv); |
661 | |
662 | return size; |
663 | } |
664 | |
665 | static void |
666 | dmminphys(struct buf *bp) |
667 | { |
668 | |
669 | bp->b_bcount = MIN(bp->b_bcount, MAXPHYS); |
670 | } |
671 | |
672 | void |
673 | dmgetproperties(struct disk *disk, dm_table_head_t *head) |
674 | { |
675 | uint64_t numsec; |
676 | unsigned secsize; |
677 | |
678 | dm_table_disksize(head, &numsec, &secsize); |
679 | |
680 | struct disk_geom *dg = &disk->dk_geom; |
681 | |
682 | memset(dg, 0, sizeof(*dg)); |
683 | dg->dg_secperunit = numsec; |
684 | dg->dg_secsize = secsize; |
685 | dg->dg_nsectors = 32; |
686 | dg->dg_ntracks = 64; |
687 | |
688 | disk_set_info(NULL, disk, "ESDI" ); |
689 | } |
690 | |