xref: /dflybsd-src/sys/dev/disk/dm/device-mapper.c (revision f6221ad16ba48c758e3a4b1e90e6c92e8e9b3162)
1ff56536eSAlex Hornung /*        $NetBSD: device-mapper.c,v 1.22 2010/03/26 15:46:04 jakllsch Exp $ */
2ff56536eSAlex Hornung 
3ff56536eSAlex Hornung /*
4ff56536eSAlex Hornung  * Copyright (c) 2010 The NetBSD Foundation, Inc.
5ff56536eSAlex Hornung  * All rights reserved.
6ff56536eSAlex Hornung  *
7ff56536eSAlex Hornung  * This code is derived from software contributed to The NetBSD Foundation
8ff56536eSAlex Hornung  * by Adam Hamsik.
9ff56536eSAlex Hornung  *
10ff56536eSAlex Hornung  * Redistribution and use in source and binary forms, with or without
11ff56536eSAlex Hornung  * modification, are permitted provided that the following conditions
12ff56536eSAlex Hornung  * are met:
13ff56536eSAlex Hornung  * 1. Redistributions of source code must retain the above copyright
14ff56536eSAlex Hornung  *    notice, this list of conditions and the following disclaimer.
15ff56536eSAlex Hornung  * 2. Redistributions in binary form must reproduce the above copyright
16ff56536eSAlex Hornung  *    notice, this list of conditions and the following disclaimer in the
17ff56536eSAlex Hornung  *    documentation and/or other materials provided with the distribution.
18ff56536eSAlex Hornung  *
19ff56536eSAlex Hornung  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20ff56536eSAlex Hornung  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21ff56536eSAlex Hornung  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22ff56536eSAlex Hornung  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23ff56536eSAlex Hornung  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24ff56536eSAlex Hornung  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25ff56536eSAlex Hornung  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26ff56536eSAlex Hornung  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27ff56536eSAlex Hornung  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28ff56536eSAlex Hornung  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29ff56536eSAlex Hornung  * POSSIBILITY OF SUCH DAMAGE.
30ff56536eSAlex Hornung  */
31ff56536eSAlex Hornung 
32ff56536eSAlex Hornung /*
33ff56536eSAlex Hornung  * I want to say thank you to all people who helped me with this project.
34ff56536eSAlex Hornung  */
35ff56536eSAlex Hornung 
36ff56536eSAlex Hornung #include <sys/types.h>
37ff56536eSAlex Hornung #include <sys/param.h>
38ff56536eSAlex Hornung 
39ff56536eSAlex Hornung #include <sys/buf.h>
40ff56536eSAlex Hornung #include <sys/conf.h>
41ff56536eSAlex Hornung #include <sys/device.h>
42ff56536eSAlex Hornung #include <sys/disk.h>
43ff56536eSAlex Hornung #include <sys/disklabel.h>
445b279a20SAlex Hornung #include <sys/dtype.h>
45ff56536eSAlex Hornung #include <sys/ioccom.h>
465b279a20SAlex Hornung #include <sys/malloc.h>
475b279a20SAlex Hornung #include <sys/module.h>
48aadb5a11SAlex Hornung #include <sys/sysctl.h>
49ff56536eSAlex Hornung 
50ff56536eSAlex Hornung #include "netbsd-dm.h"
51ff56536eSAlex Hornung #include "dm.h"
52ff56536eSAlex Hornung 
535b279a20SAlex Hornung static	d_ioctl_t	dmioctl;
545b279a20SAlex Hornung static	d_open_t	dmopen;
555b279a20SAlex Hornung static	d_close_t	dmclose;
565b279a20SAlex Hornung static	d_psize_t	dmsize;
575b279a20SAlex Hornung static	d_strategy_t	dmstrategy;
58ff56536eSAlex Hornung 
59ff56536eSAlex Hornung /* attach and detach routines */
60ff56536eSAlex Hornung void dmattach(int);
615b279a20SAlex Hornung static int dm_modcmd(module_t mod, int cmd, void *unused);
62ff56536eSAlex Hornung static int dmdestroy(void);
63ff56536eSAlex Hornung 
64ff56536eSAlex Hornung static void dm_doinit(void);
65ff56536eSAlex Hornung 
66ff56536eSAlex Hornung static int dm_cmd_to_fun(prop_dictionary_t);
675b279a20SAlex Hornung static int disk_ioctl_switch(cdev_t, u_long, void *);
68ff56536eSAlex Hornung static int dm_ioctl_switch(u_long);
695b279a20SAlex Hornung #if 0
70ff56536eSAlex Hornung static void dmminphys(struct buf *);
715b279a20SAlex Hornung #endif
72ff56536eSAlex Hornung 
73ff56536eSAlex Hornung /* ***Variable-definitions*** */
745b279a20SAlex Hornung struct dev_ops dm_ops = {
755b279a20SAlex Hornung 	{ "dm", 0, D_DISK |
765b279a20SAlex Hornung 	    D_MPSAFE_READ | D_MPSAFE_WRITE | D_MPSAFE_IOCTL },
77ff56536eSAlex Hornung 	.d_open		= dmopen,
78ff56536eSAlex Hornung 	.d_close	= dmclose,
795b279a20SAlex Hornung 	.d_read 	= physread,
805b279a20SAlex Hornung 	.d_write 	= physwrite,
815b279a20SAlex Hornung 	.d_ioctl	= dmioctl,
82ff56536eSAlex Hornung 	.d_strategy	= dmstrategy,
83ff56536eSAlex Hornung 	.d_psize	= dmsize,
845b279a20SAlex Hornung /* D_DISK */
85ff56536eSAlex Hornung };
86ff56536eSAlex Hornung 
875b279a20SAlex Hornung MALLOC_DEFINE(M_DM, "dm", "Device Mapper allocations");
88ff56536eSAlex Hornung 
89aadb5a11SAlex Hornung int dm_debug_level = 0;
90aadb5a11SAlex Hornung 
91ff56536eSAlex Hornung extern uint64_t dm_dev_counter;
92ff56536eSAlex Hornung 
935b279a20SAlex Hornung static cdev_t dmcdev;
945b279a20SAlex Hornung 
955b279a20SAlex Hornung static moduledata_t dm_mod = {
965b279a20SAlex Hornung     "dm",
975b279a20SAlex Hornung     dm_modcmd,
985b279a20SAlex Hornung     NULL
995b279a20SAlex Hornung };
1005b279a20SAlex Hornung DECLARE_MODULE(dm, dm_mod, SI_SUB_RAID, SI_ORDER_ANY);
1015b279a20SAlex Hornung 
102ff56536eSAlex Hornung /*
103ff56536eSAlex Hornung  * This array is used to translate cmd to function pointer.
104ff56536eSAlex Hornung  *
105ff56536eSAlex Hornung  * Interface between libdevmapper and lvm2tools uses different
106ff56536eSAlex Hornung  * names for one IOCTL call because libdevmapper do another thing
107ff56536eSAlex Hornung  * then. When I run "info" or "mknodes" libdevmapper will send same
108ff56536eSAlex Hornung  * ioctl to kernel but will do another things in userspace.
109ff56536eSAlex Hornung  *
110ff56536eSAlex Hornung  */
11161413047SAlex Hornung static struct cmd_function cmd_fn[] = {
112ff56536eSAlex Hornung 		{ .cmd = "version", .fn = dm_get_version_ioctl},
113ff56536eSAlex Hornung 		{ .cmd = "targets", .fn = dm_list_versions_ioctl},
114ff56536eSAlex Hornung 		{ .cmd = "create",  .fn = dm_dev_create_ioctl},
115ff56536eSAlex Hornung 		{ .cmd = "info",    .fn = dm_dev_status_ioctl},
116ff56536eSAlex Hornung 		{ .cmd = "mknodes", .fn = dm_dev_status_ioctl},
117ff56536eSAlex Hornung 		{ .cmd = "names",   .fn = dm_dev_list_ioctl},
118ff56536eSAlex Hornung 		{ .cmd = "suspend", .fn = dm_dev_suspend_ioctl},
119ff56536eSAlex Hornung 		{ .cmd = "remove",  .fn = dm_dev_remove_ioctl},
120ff56536eSAlex Hornung 		{ .cmd = "rename",  .fn = dm_dev_rename_ioctl},
121ff56536eSAlex Hornung 		{ .cmd = "resume",  .fn = dm_dev_resume_ioctl},
122ff56536eSAlex Hornung 		{ .cmd = "clear",   .fn = dm_table_clear_ioctl},
123ff56536eSAlex Hornung 		{ .cmd = "deps",    .fn = dm_table_deps_ioctl},
124ff56536eSAlex Hornung 		{ .cmd = "reload",  .fn = dm_table_load_ioctl},
125ff56536eSAlex Hornung 		{ .cmd = "status",  .fn = dm_table_status_ioctl},
126ff56536eSAlex Hornung 		{ .cmd = "table",   .fn = dm_table_status_ioctl},
127ff56536eSAlex Hornung 		{NULL, NULL}
128ff56536eSAlex Hornung };
129ff56536eSAlex Hornung 
130ff56536eSAlex Hornung /* New module handle routine */
131ff56536eSAlex Hornung static int
1325b279a20SAlex Hornung dm_modcmd(module_t mod, int cmd, void *unused)
133ff56536eSAlex Hornung {
134ff56536eSAlex Hornung 	int error, bmajor, cmajor;
135ff56536eSAlex Hornung 
136ff56536eSAlex Hornung 	error = 0;
137ff56536eSAlex Hornung 	bmajor = -1;
138ff56536eSAlex Hornung 	cmajor = -1;
139ff56536eSAlex Hornung 
140ff56536eSAlex Hornung 	switch (cmd) {
1415b279a20SAlex Hornung 	case MOD_LOAD:
142ff56536eSAlex Hornung 		dm_doinit();
143e8e2bcdaSAlex Hornung 		kprintf("Device Mapper version %d.%d.%d loaded\n",
1445b279a20SAlex Hornung 		    DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL);
145ff56536eSAlex Hornung 		break;
146ff56536eSAlex Hornung 
1475b279a20SAlex Hornung 	case MOD_UNLOAD:
148ff56536eSAlex Hornung 		/*
149ff56536eSAlex Hornung 		 * Disable unloading of dm module if there are any devices
150ff56536eSAlex Hornung 		 * defined in driver. This is probably too strong we need
151ff56536eSAlex Hornung 		 * to disable auto-unload only if there is mounted dm device
152ff56536eSAlex Hornung 		 * present.
153ff56536eSAlex Hornung 		 */
154ff56536eSAlex Hornung 		if (dm_dev_counter > 0)
155ff56536eSAlex Hornung 			return EBUSY;
156ff56536eSAlex Hornung 
157ff56536eSAlex Hornung 		error = dmdestroy();
158ff56536eSAlex Hornung 		if (error)
159ff56536eSAlex Hornung 			break;
160e8e2bcdaSAlex Hornung 		kprintf("Device Mapper unloaded\n");
161ff56536eSAlex Hornung 		break;
162ff56536eSAlex Hornung 
163ff56536eSAlex Hornung 	default:
1645b279a20SAlex Hornung 		break;
165ff56536eSAlex Hornung 	}
166ff56536eSAlex Hornung 
167ff56536eSAlex Hornung 	return error;
168ff56536eSAlex Hornung }
169ff56536eSAlex Hornung 
170ff56536eSAlex Hornung /*
171ff56536eSAlex Hornung  * dm_detach:
172ff56536eSAlex Hornung  *
173ff56536eSAlex Hornung  *	Autoconfiguration detach function for pseudo-device glue.
174ff56536eSAlex Hornung  * This routine is called by dm_ioctl::dm_dev_remove_ioctl and by autoconf to
175ff56536eSAlex Hornung  * remove devices created in device-mapper.
176ff56536eSAlex Hornung  */
1775b279a20SAlex Hornung int
1785b279a20SAlex Hornung dm_detach(dm_dev_t *dmv)
179ff56536eSAlex Hornung {
1805b279a20SAlex Hornung 	disable_dev(dmv);
181ff56536eSAlex Hornung 
182ff56536eSAlex Hornung 	/* Destroy active table first.  */
183ff56536eSAlex Hornung 	dm_table_destroy(&dmv->table_head, DM_TABLE_ACTIVE);
184ff56536eSAlex Hornung 
185ff56536eSAlex Hornung 	/* Destroy inactive table if exits, too. */
186ff56536eSAlex Hornung 	dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
187ff56536eSAlex Hornung 
188ff56536eSAlex Hornung 	dm_table_head_destroy(&dmv->table_head);
189ff56536eSAlex Hornung 
1905b279a20SAlex Hornung 	destroy_dev(dmv->devt);
191ff56536eSAlex Hornung 
192ff56536eSAlex Hornung 	/* Destroy device */
193ff56536eSAlex Hornung 	(void)dm_dev_free(dmv);
194ff56536eSAlex Hornung 
195ff56536eSAlex Hornung 	/* Decrement device counter After removing device */
1965b279a20SAlex Hornung 	--dm_dev_counter; /* XXX: was atomic 64 */
197ff56536eSAlex Hornung 
198ff56536eSAlex Hornung 	return 0;
199ff56536eSAlex Hornung }
200ff56536eSAlex Hornung 
201ff56536eSAlex Hornung static void
202ff56536eSAlex Hornung dm_doinit(void)
203ff56536eSAlex Hornung {
204ff56536eSAlex Hornung 	dm_target_init();
205ff56536eSAlex Hornung 	dm_dev_init();
206ff56536eSAlex Hornung 	dm_pdev_init();
2075b279a20SAlex Hornung 	dmcdev = make_dev(&dm_ops, 0, UID_ROOT, GID_OPERATOR, 0640, "mapper/control");
208ff56536eSAlex Hornung }
209ff56536eSAlex Hornung 
210ff56536eSAlex Hornung /* Destroy routine */
211ff56536eSAlex Hornung static int
212ff56536eSAlex Hornung dmdestroy(void)
213ff56536eSAlex Hornung {
2145b279a20SAlex Hornung 	destroy_dev(dmcdev);
215ff56536eSAlex Hornung 
216ff56536eSAlex Hornung 	dm_dev_destroy();
217ff56536eSAlex Hornung 	dm_pdev_destroy();
218ff56536eSAlex Hornung 	dm_target_destroy();
219ff56536eSAlex Hornung 
220ff56536eSAlex Hornung 	return 0;
221ff56536eSAlex Hornung }
222ff56536eSAlex Hornung 
223ff56536eSAlex Hornung static int
2245b279a20SAlex Hornung dmopen(struct dev_open_args *ap)
225ff56536eSAlex Hornung {
226ff56536eSAlex Hornung 
2275b279a20SAlex Hornung 	aprint_debug("dm open routine called %" PRIu32 "\n",
2285b279a20SAlex Hornung 	    minor(ap->a_head.a_dev));
229ff56536eSAlex Hornung 	return 0;
230ff56536eSAlex Hornung }
231ff56536eSAlex Hornung 
232ff56536eSAlex Hornung static int
2335b279a20SAlex Hornung dmclose(struct dev_close_args *ap)
234ff56536eSAlex Hornung {
235ff56536eSAlex Hornung 
2365b279a20SAlex Hornung 	aprint_debug("dm close routine called %" PRIu32 "\n",
2375b279a20SAlex Hornung 	    minor(ap->a_head.a_dev));
238ff56536eSAlex Hornung 	return 0;
239ff56536eSAlex Hornung }
240ff56536eSAlex Hornung 
241ff56536eSAlex Hornung 
242ff56536eSAlex Hornung static int
2435b279a20SAlex Hornung dmioctl(struct dev_ioctl_args *ap)
244ff56536eSAlex Hornung {
2455b279a20SAlex Hornung 	cdev_t dev = ap->a_head.a_dev;
2465b279a20SAlex Hornung 	u_long cmd = ap->a_cmd;
2475b279a20SAlex Hornung 	void *data = ap->a_data;
2485b279a20SAlex Hornung 
249ff56536eSAlex Hornung 	int r;
250ff56536eSAlex Hornung 	prop_dictionary_t dm_dict_in;
251ff56536eSAlex Hornung 
252ff56536eSAlex Hornung 	r = 0;
253ff56536eSAlex Hornung 
254ff56536eSAlex Hornung 	aprint_debug("dmioctl called\n");
255ff56536eSAlex Hornung 
2565b279a20SAlex Hornung 	KKASSERT(data != NULL);
257ff56536eSAlex Hornung 
258ff56536eSAlex Hornung 	if (( r = disk_ioctl_switch(dev, cmd, data)) == ENOTTY) {
259ff56536eSAlex Hornung 		struct plistref *pref = (struct plistref *) data;
260ff56536eSAlex Hornung 
261ff56536eSAlex Hornung 		/* Check if we were called with NETBSD_DM_IOCTL ioctl
262ff56536eSAlex Hornung 		   otherwise quit. */
263ff56536eSAlex Hornung 		if ((r = dm_ioctl_switch(cmd)) != 0)
264ff56536eSAlex Hornung 			return r;
265ff56536eSAlex Hornung 
266ff56536eSAlex Hornung 		if((r = prop_dictionary_copyin_ioctl(pref, cmd, &dm_dict_in)) != 0)
267ff56536eSAlex Hornung 			return r;
268ff56536eSAlex Hornung 
269ff56536eSAlex Hornung 		if ((r = dm_check_version(dm_dict_in)) != 0)
270ff56536eSAlex Hornung 			goto cleanup_exit;
271ff56536eSAlex Hornung 
272ff56536eSAlex Hornung 		/* run ioctl routine */
273ff56536eSAlex Hornung 		if ((r = dm_cmd_to_fun(dm_dict_in)) != 0)
274ff56536eSAlex Hornung 			goto cleanup_exit;
275ff56536eSAlex Hornung 
276ff56536eSAlex Hornung cleanup_exit:
277ff56536eSAlex Hornung 		r = prop_dictionary_copyout_ioctl(pref, cmd, dm_dict_in);
278ff56536eSAlex Hornung 		prop_object_release(dm_dict_in);
279ff56536eSAlex Hornung 	}
280ff56536eSAlex Hornung 
281ff56536eSAlex Hornung 	return r;
282ff56536eSAlex Hornung }
283ff56536eSAlex Hornung 
284ff56536eSAlex Hornung /*
285ff56536eSAlex Hornung  * Translate command sent from libdevmapper to func.
286ff56536eSAlex Hornung  */
287ff56536eSAlex Hornung static int
288ff56536eSAlex Hornung dm_cmd_to_fun(prop_dictionary_t dm_dict){
289ff56536eSAlex Hornung 	int i, r;
290ff56536eSAlex Hornung 	prop_string_t command;
291ff56536eSAlex Hornung 
292ff56536eSAlex Hornung 	r = 0;
293ff56536eSAlex Hornung 
294ff56536eSAlex Hornung 	if ((command = prop_dictionary_get(dm_dict, DM_IOCTL_COMMAND)) == NULL)
295ff56536eSAlex Hornung 		return EINVAL;
296ff56536eSAlex Hornung 
297ff56536eSAlex Hornung 	for(i = 0; cmd_fn[i].cmd != NULL; i++)
298ff56536eSAlex Hornung 		if (prop_string_equals_cstring(command, cmd_fn[i].cmd))
299ff56536eSAlex Hornung 			break;
300ff56536eSAlex Hornung 
301ff56536eSAlex Hornung 	if (cmd_fn[i].cmd == NULL)
302ff56536eSAlex Hornung 		return EINVAL;
303ff56536eSAlex Hornung 
304ff56536eSAlex Hornung 	aprint_debug("ioctl %s called\n", cmd_fn[i].cmd);
305ff56536eSAlex Hornung 	r = cmd_fn[i].fn(dm_dict);
306ff56536eSAlex Hornung 
307ff56536eSAlex Hornung 	return r;
308ff56536eSAlex Hornung }
309ff56536eSAlex Hornung 
310ff56536eSAlex Hornung /* Call apropriate ioctl handler function. */
311ff56536eSAlex Hornung static int
312ff56536eSAlex Hornung dm_ioctl_switch(u_long cmd)
313ff56536eSAlex Hornung {
314ff56536eSAlex Hornung 
315ff56536eSAlex Hornung 	switch(cmd) {
316ff56536eSAlex Hornung 
317ff56536eSAlex Hornung 	case NETBSD_DM_IOCTL:
318ff56536eSAlex Hornung 		aprint_debug("dm NetBSD_DM_IOCTL called\n");
319ff56536eSAlex Hornung 		break;
320ff56536eSAlex Hornung 	default:
321ff56536eSAlex Hornung 		 aprint_debug("dm unknown ioctl called\n");
322ff56536eSAlex Hornung 		 return ENOTTY;
323ff56536eSAlex Hornung 		 break; /* NOT REACHED */
324ff56536eSAlex Hornung 	}
325ff56536eSAlex Hornung 
326ff56536eSAlex Hornung 	 return 0;
327ff56536eSAlex Hornung }
328ff56536eSAlex Hornung 
329ff56536eSAlex Hornung  /*
330ff56536eSAlex Hornung   * Check for disk specific ioctls.
331ff56536eSAlex Hornung   */
332ff56536eSAlex Hornung 
333ff56536eSAlex Hornung static int
3345b279a20SAlex Hornung disk_ioctl_switch(cdev_t dev, u_long cmd, void *data)
335ff56536eSAlex Hornung {
336ff56536eSAlex Hornung 	dm_dev_t *dmv;
337ff56536eSAlex Hornung 
338ff56536eSAlex Hornung 	/* disk ioctls make sense only on block devices */
339ff56536eSAlex Hornung 	if (minor(dev) == 0)
340ff56536eSAlex Hornung 		return ENOTTY;
341ff56536eSAlex Hornung 
342ff56536eSAlex Hornung 	switch(cmd) {
3435b279a20SAlex Hornung 	case DIOCGPART:
344ff56536eSAlex Hornung 	{
3455b279a20SAlex Hornung 		struct partinfo *dpart;
3465b279a20SAlex Hornung 		u_int64_t size;
3475b279a20SAlex Hornung 		dpart = (void *)data;
3485b279a20SAlex Hornung 		bzero(dpart, sizeof(*dpart));
349ff56536eSAlex Hornung 
350ff56536eSAlex Hornung 		if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL)
351ff56536eSAlex Hornung 			return ENODEV;
3525b279a20SAlex Hornung 		if (dmv->diskp->d_info.d_media_blksize == 0) {
353ff56536eSAlex Hornung 			dm_dev_unbusy(dmv);
354ff56536eSAlex Hornung 			return ENOTSUP;
3555b279a20SAlex Hornung 		} else {
3565b279a20SAlex Hornung 			size = dm_table_size(&dmv->table_head);
3575b279a20SAlex Hornung 			dpart->media_offset  = 0;
3585b279a20SAlex Hornung 			dpart->media_size    = size * DEV_BSIZE;
3595b279a20SAlex Hornung 			dpart->media_blocks  = size;
3605b279a20SAlex Hornung 			dpart->media_blksize = DEV_BSIZE;
3615b279a20SAlex Hornung 			dpart->fstype = FS_BSDFFS;
3625b279a20SAlex Hornung 		}
363ff56536eSAlex Hornung 		dm_dev_unbusy(dmv);
364ff56536eSAlex Hornung 		break;
365ff56536eSAlex Hornung 	}
366ff56536eSAlex Hornung 
367ff56536eSAlex Hornung 	default:
368ff56536eSAlex Hornung 		aprint_debug("unknown disk_ioctl called\n");
369ff56536eSAlex Hornung 		return ENOTTY;
370ff56536eSAlex Hornung 		break; /* NOT REACHED */
371ff56536eSAlex Hornung 	}
372ff56536eSAlex Hornung 
373ff56536eSAlex Hornung 	return 0;
374ff56536eSAlex Hornung }
375ff56536eSAlex Hornung 
376ff56536eSAlex Hornung /*
377ff56536eSAlex Hornung  * Do all IO operations on dm logical devices.
378ff56536eSAlex Hornung  */
3795b279a20SAlex Hornung static int
3805b279a20SAlex Hornung dmstrategy(struct dev_strategy_args *ap)
381ff56536eSAlex Hornung {
3825b279a20SAlex Hornung 	cdev_t dev = ap->a_head.a_dev;
3835b279a20SAlex Hornung 	struct bio *bio = ap->a_bio;
3845b279a20SAlex Hornung 	struct buf *bp = bio->bio_buf;
3853adc52bcSMatthew Dillon 	int bypass;
3865b279a20SAlex Hornung 
387ff56536eSAlex Hornung 	dm_dev_t *dmv;
388ff56536eSAlex Hornung 	dm_table_t  *tbl;
389ff56536eSAlex Hornung 	dm_table_entry_t *table_en;
390ff56536eSAlex Hornung 	struct buf *nestbuf;
391ff56536eSAlex Hornung 
392ff56536eSAlex Hornung 	uint32_t dev_type;
393ff56536eSAlex Hornung 
394ff56536eSAlex Hornung 	uint64_t buf_start, buf_len, issued_len;
395ff56536eSAlex Hornung 	uint64_t table_start, table_end;
396ff56536eSAlex Hornung 	uint64_t start, end;
397ff56536eSAlex Hornung 
3985b279a20SAlex Hornung 	buf_start = bio->bio_offset;
399ff56536eSAlex Hornung 	buf_len = bp->b_bcount;
400ff56536eSAlex Hornung 
401ff56536eSAlex Hornung 	tbl = NULL;
402ff56536eSAlex Hornung 
403ff56536eSAlex Hornung 	table_end = 0;
404ff56536eSAlex Hornung 	dev_type = 0;
405ff56536eSAlex Hornung 	issued_len = 0;
406ff56536eSAlex Hornung 
4075b279a20SAlex Hornung 	if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) {
408ff56536eSAlex Hornung 		bp->b_error = EIO;
409ff56536eSAlex Hornung 		bp->b_resid = bp->b_bcount;
4105b279a20SAlex Hornung 		biodone(bio);
4115b279a20SAlex Hornung 		return 0;
412ff56536eSAlex Hornung 	}
413ff56536eSAlex Hornung 
4143adc52bcSMatthew Dillon 	switch(bp->b_cmd) {
4153adc52bcSMatthew Dillon 	case BUF_CMD_READ:
4163adc52bcSMatthew Dillon 	case BUF_CMD_WRITE:
4173adc52bcSMatthew Dillon 	case BUF_CMD_FREEBLKS:
4183adc52bcSMatthew Dillon 		bypass = 0;
4193adc52bcSMatthew Dillon 		break;
4203adc52bcSMatthew Dillon 	case BUF_CMD_FLUSH:
4213adc52bcSMatthew Dillon 		bypass = 1;
4223adc52bcSMatthew Dillon 		KKASSERT(buf_len == 0);
4233adc52bcSMatthew Dillon 		break;
4243adc52bcSMatthew Dillon 	default:
4253adc52bcSMatthew Dillon 		dm_dev_unbusy(dmv);
4263adc52bcSMatthew Dillon 		bp->b_error = EIO;
4273adc52bcSMatthew Dillon 		bp->b_resid = bp->b_bcount;
4283adc52bcSMatthew Dillon 		biodone(bio);
4293adc52bcSMatthew Dillon 		return 0;
4303adc52bcSMatthew Dillon 	}
4313adc52bcSMatthew Dillon 
4323adc52bcSMatthew Dillon 	if (bypass == 0 &&
4333adc52bcSMatthew Dillon 	    bounds_check_with_mediasize(bio, DEV_BSIZE,
434ff56536eSAlex Hornung 					dm_table_size(&dmv->table_head)) <= 0) {
435ff56536eSAlex Hornung 		dm_dev_unbusy(dmv);
436ff56536eSAlex Hornung 		bp->b_resid = bp->b_bcount;
4375b279a20SAlex Hornung 		biodone(bio);
4385b279a20SAlex Hornung 		return 0;
439ff56536eSAlex Hornung 	}
440ff56536eSAlex Hornung 
441ff56536eSAlex Hornung 	/* Select active table */
442ff56536eSAlex Hornung 	tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE);
443ff56536eSAlex Hornung 
4443adc52bcSMatthew Dillon 	nestiobuf_init(bio);
445ff56536eSAlex Hornung 
446ff56536eSAlex Hornung 	/*
447ff56536eSAlex Hornung 	 * Find out what tables I want to select.
448ff56536eSAlex Hornung 	 */
4493adc52bcSMatthew Dillon 	SLIST_FOREACH(table_en, tbl, next) {
450ff56536eSAlex Hornung 		/*
4513adc52bcSMatthew Dillon 		 * I need need number of bytes not blocks.
452ff56536eSAlex Hornung 		 */
4533adc52bcSMatthew Dillon 		table_start = table_en->start * DEV_BSIZE;
454ff56536eSAlex Hornung 		table_end = table_start + (table_en->length) * DEV_BSIZE;
455ff56536eSAlex Hornung 
4563adc52bcSMatthew Dillon 		/*
4573adc52bcSMatthew Dillon 		 * Calculate the start and end
4583adc52bcSMatthew Dillon 		 */
459ff56536eSAlex Hornung 		start = MAX(table_start, buf_start);
460ff56536eSAlex Hornung 		end = MIN(table_end, buf_start + buf_len);
461ff56536eSAlex Hornung 
462ff56536eSAlex Hornung 		aprint_debug("----------------------------------------\n");
463ff56536eSAlex Hornung 		aprint_debug("table_start %010" PRIu64", table_end %010"
464ff56536eSAlex Hornung 		    PRIu64 "\n", table_start, table_end);
465ff56536eSAlex Hornung 		aprint_debug("buf_start %010" PRIu64", buf_len %010"
466ff56536eSAlex Hornung 		    PRIu64"\n", buf_start, buf_len);
467ff56536eSAlex Hornung 		aprint_debug("start-buf_start %010"PRIu64", end %010"
468ff56536eSAlex Hornung 		    PRIu64"\n", start - buf_start, end);
469ff56536eSAlex Hornung 		aprint_debug("start %010" PRIu64" , end %010"
470ff56536eSAlex Hornung                     PRIu64"\n", start, end);
471ff56536eSAlex Hornung 		aprint_debug("\n----------------------------------------\n");
472ff56536eSAlex Hornung 
4733adc52bcSMatthew Dillon 		if (bypass) {
4745b279a20SAlex Hornung 			nestbuf = getpbuf(NULL);
475*f6221ad1SMatthew Dillon 			nestbuf->b_flags |= bio->bio_buf->b_flags & B_HASBOGUS;
476ff56536eSAlex Hornung 
4773adc52bcSMatthew Dillon 			nestiobuf_add(bio, nestbuf, 0, 0);
4783adc52bcSMatthew Dillon 			nestbuf->b_bio1.bio_offset = 0;
4793adc52bcSMatthew Dillon 			table_en->target->strategy(table_en, nestbuf);
4803adc52bcSMatthew Dillon 		} else if (start < end) {
4813adc52bcSMatthew Dillon 			nestbuf = getpbuf(NULL);
482*f6221ad1SMatthew Dillon 			nestbuf->b_flags |= bio->bio_buf->b_flags & B_HASBOGUS;
483*f6221ad1SMatthew Dillon 
4843adc52bcSMatthew Dillon 			nestiobuf_add(bio, nestbuf,
4853adc52bcSMatthew Dillon 				      start - buf_start, (end - start));
486ff56536eSAlex Hornung 			issued_len += end - start;
487ff56536eSAlex Hornung 
4885b279a20SAlex Hornung 			nestbuf->b_bio1.bio_offset = (start - table_start);
489ff56536eSAlex Hornung 			table_en->target->strategy(table_en, nestbuf);
490ff56536eSAlex Hornung 		}
491ff56536eSAlex Hornung 	}
492ff56536eSAlex Hornung 
493ff56536eSAlex Hornung 	if (issued_len < buf_len)
4943adc52bcSMatthew Dillon 		nestiobuf_error(bio, EINVAL);
4953adc52bcSMatthew Dillon 	nestiobuf_start(bio);
496ff56536eSAlex Hornung 	dm_table_release(&dmv->table_head, DM_TABLE_ACTIVE);
497ff56536eSAlex Hornung 	dm_dev_unbusy(dmv);
498ff56536eSAlex Hornung 
4995b279a20SAlex Hornung 	return 0;
500ff56536eSAlex Hornung }
501ff56536eSAlex Hornung 
502ff56536eSAlex Hornung static int
5035b279a20SAlex Hornung dmsize(struct dev_psize_args *ap)
504ff56536eSAlex Hornung {
5055b279a20SAlex Hornung 	cdev_t dev = ap->a_head.a_dev;
506ff56536eSAlex Hornung 	dm_dev_t *dmv;
507ff56536eSAlex Hornung 	uint64_t size;
508ff56536eSAlex Hornung 
509ff56536eSAlex Hornung 	size = 0;
510ff56536eSAlex Hornung 
511ff56536eSAlex Hornung 	if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL)
512ff56536eSAlex Hornung 			return -ENOENT;
513ff56536eSAlex Hornung 
514ff56536eSAlex Hornung 	size = dm_table_size(&dmv->table_head);
515ff56536eSAlex Hornung 	dm_dev_unbusy(dmv);
516ff56536eSAlex Hornung 
517ff56536eSAlex Hornung   	return size;
518ff56536eSAlex Hornung }
519ff56536eSAlex Hornung 
5205b279a20SAlex Hornung #if 0
521ff56536eSAlex Hornung static void
522ff56536eSAlex Hornung dmminphys(struct buf *bp)
523ff56536eSAlex Hornung {
524ff56536eSAlex Hornung 
525ff56536eSAlex Hornung 	bp->b_bcount = MIN(bp->b_bcount, MAXPHYS);
526ff56536eSAlex Hornung }
5275b279a20SAlex Hornung #endif
5285b279a20SAlex Hornung 
5295b279a20SAlex Hornung void
5305b279a20SAlex Hornung dmsetdiskinfo(struct disk *disk, dm_table_head_t *head)
5315b279a20SAlex Hornung {
5325b279a20SAlex Hornung 	struct disk_info info;
5335b279a20SAlex Hornung 	int dmp_size;
5345b279a20SAlex Hornung 
5355b279a20SAlex Hornung 	dmp_size = dm_table_size(head);
5365b279a20SAlex Hornung 
5375b279a20SAlex Hornung 	bzero(&info, sizeof(struct disk_info));
5385b279a20SAlex Hornung 	info.d_media_blksize = DEV_BSIZE;
5395b279a20SAlex Hornung 	info.d_media_blocks = dmp_size;
5405b279a20SAlex Hornung 	info.d_media_size = dmp_size * DEV_BSIZE;
5415b279a20SAlex Hornung 	info.d_dsflags = DSO_MBRQUIET; /* XXX */
5425b279a20SAlex Hornung 	info.d_secpertrack = 32;
5435b279a20SAlex Hornung 	info.d_nheads = 64;
5445b279a20SAlex Hornung 	info.d_secpercyl = info.d_secpertrack * info.d_nheads;
5455b279a20SAlex Hornung 	info.d_ncylinders = dmp_size / 2048;
5465b279a20SAlex Hornung 	bcopy(&info, &disk->d_info, sizeof(disk->d_info));
5475b279a20SAlex Hornung }
5485b279a20SAlex Hornung 
5495b279a20SAlex Hornung prop_dictionary_t
5505b279a20SAlex Hornung dmgetdiskinfo(struct disk *disk)
5515b279a20SAlex Hornung {
5525b279a20SAlex Hornung 	prop_dictionary_t disk_info, geom;
5535b279a20SAlex Hornung 	struct disk_info *pinfo;
5545b279a20SAlex Hornung 
5555b279a20SAlex Hornung 	pinfo = &disk->d_info;
5565b279a20SAlex Hornung 
5575b279a20SAlex Hornung 	disk_info = prop_dictionary_create();
5585b279a20SAlex Hornung 	geom = prop_dictionary_create();
5595b279a20SAlex Hornung 
5605b279a20SAlex Hornung 	prop_dictionary_set_cstring_nocopy(disk_info, "type", "ESDI");
5615b279a20SAlex Hornung 	prop_dictionary_set_uint64(geom, "sectors-per-unit", pinfo->d_media_blocks);
5625b279a20SAlex Hornung 	prop_dictionary_set_uint32(geom, "sector-size",
5635b279a20SAlex Hornung 	    DEV_BSIZE /* XXX 512? */);
5645b279a20SAlex Hornung 	prop_dictionary_set_uint32(geom, "sectors-per-track", 32);
5655b279a20SAlex Hornung 	prop_dictionary_set_uint32(geom, "tracks-per-cylinder", 64);
5665b279a20SAlex Hornung 	prop_dictionary_set_uint32(geom, "cylinders-per-unit",
5675b279a20SAlex Hornung 	    pinfo->d_media_blocks / 2048);
5685b279a20SAlex Hornung 	prop_dictionary_set(disk_info, "geometry", geom);
5695b279a20SAlex Hornung 	prop_object_release(geom);
5705b279a20SAlex Hornung 
5715b279a20SAlex Hornung 	return disk_info;
5725b279a20SAlex Hornung }
573ff56536eSAlex Hornung 
574ff56536eSAlex Hornung void
575ff56536eSAlex Hornung dmgetproperties(struct disk *disk, dm_table_head_t *head)
576ff56536eSAlex Hornung {
5775b279a20SAlex Hornung #if 0
578ff56536eSAlex Hornung 	prop_dictionary_t disk_info, odisk_info, geom;
579ff56536eSAlex Hornung 	int dmp_size;
580ff56536eSAlex Hornung 
581ff56536eSAlex Hornung 	dmp_size = dm_table_size(head);
582ff56536eSAlex Hornung 	disk_info = prop_dictionary_create();
583ff56536eSAlex Hornung 	geom = prop_dictionary_create();
584ff56536eSAlex Hornung 
585ff56536eSAlex Hornung 	prop_dictionary_set_cstring_nocopy(disk_info, "type", "ESDI");
586ff56536eSAlex Hornung 	prop_dictionary_set_uint64(geom, "sectors-per-unit", dmp_size);
587ff56536eSAlex Hornung 	prop_dictionary_set_uint32(geom, "sector-size",
588ff56536eSAlex Hornung 	    DEV_BSIZE /* XXX 512? */);
589ff56536eSAlex Hornung 	prop_dictionary_set_uint32(geom, "sectors-per-track", 32);
590ff56536eSAlex Hornung 	prop_dictionary_set_uint32(geom, "tracks-per-cylinder", 64);
591ff56536eSAlex Hornung 	prop_dictionary_set_uint32(geom, "cylinders-per-unit", dmp_size / 2048);
592ff56536eSAlex Hornung 	prop_dictionary_set(disk_info, "geometry", geom);
593ff56536eSAlex Hornung 	prop_object_release(geom);
594ff56536eSAlex Hornung 
595ff56536eSAlex Hornung 	odisk_info = disk->dk_info;
596ff56536eSAlex Hornung 	disk->dk_info = disk_info;
597ff56536eSAlex Hornung 
598ff56536eSAlex Hornung 	if (odisk_info != NULL)
599ff56536eSAlex Hornung 		prop_object_release(odisk_info);
6005b279a20SAlex Hornung #endif
601ff56536eSAlex Hornung }
602aadb5a11SAlex Hornung 
603aadb5a11SAlex Hornung TUNABLE_INT("debug.dm_debug", &dm_debug_level);
604aadb5a11SAlex Hornung SYSCTL_INT(_debug, OID_AUTO, dm_debug, CTLFLAG_RW, &dm_debug_level,
605aadb5a11SAlex Hornung 	       0, "Eanble device mapper debugging");
606aadb5a11SAlex Hornung 
607