xref: /illumos-gate/usr/src/boot/common/vdisk.c (revision 22028508)
1*22028508SToomas Soome /*
2*22028508SToomas Soome  * Copyright 2019 Toomas Soome <tsoome@me.com>
3*22028508SToomas Soome  *
4*22028508SToomas Soome  * Redistribution and use in source and binary forms, with or without
5*22028508SToomas Soome  * modification, are permitted provided that the following conditions
6*22028508SToomas Soome  * are met:
7*22028508SToomas Soome  * 1. Redistributions of source code must retain the above copyright
8*22028508SToomas Soome  *    notice, this list of conditions and the following disclaimer.
9*22028508SToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
10*22028508SToomas Soome  *    notice, this list of conditions and the following disclaimer in the
11*22028508SToomas Soome  *    documentation and/or other materials provided with the distribution.
12*22028508SToomas Soome  *
13*22028508SToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14*22028508SToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15*22028508SToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16*22028508SToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17*22028508SToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18*22028508SToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19*22028508SToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20*22028508SToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21*22028508SToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22*22028508SToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23*22028508SToomas Soome  * SUCH DAMAGE.
24*22028508SToomas Soome  */
25*22028508SToomas Soome 
26*22028508SToomas Soome #include <sys/cdefs.h>
27*22028508SToomas Soome 
28*22028508SToomas Soome #include <stand.h>
29*22028508SToomas Soome #include <stdarg.h>
30*22028508SToomas Soome #include <inttypes.h>
31*22028508SToomas Soome #include <bootstrap.h>
32*22028508SToomas Soome #include <sys/disk.h>
33*22028508SToomas Soome #include <sys/errno.h>
34*22028508SToomas Soome #include <sys/queue.h>
35*22028508SToomas Soome #include <sys/param.h>
36*22028508SToomas Soome #include <disk.h>
37*22028508SToomas Soome 
38*22028508SToomas Soome static int vdisk_init(void);
39*22028508SToomas Soome static int vdisk_strategy(void *, int, daddr_t, size_t, char *, size_t *);
40*22028508SToomas Soome static int vdisk_open(struct open_file *, ...);
41*22028508SToomas Soome static int vdisk_close(struct open_file *);
42*22028508SToomas Soome static int vdisk_ioctl(struct open_file *, ulong_t, void *);
43*22028508SToomas Soome static int vdisk_print(int);
44*22028508SToomas Soome 
45*22028508SToomas Soome struct devsw vdisk_dev = {
46*22028508SToomas Soome 	.dv_name = "vdisk",
47*22028508SToomas Soome 	.dv_type = DEVT_DISK,
48*22028508SToomas Soome 	.dv_init = vdisk_init,
49*22028508SToomas Soome 	.dv_strategy = vdisk_strategy,
50*22028508SToomas Soome 	.dv_open = vdisk_open,
51*22028508SToomas Soome 	.dv_close = vdisk_close,
52*22028508SToomas Soome 	.dv_ioctl = vdisk_ioctl,
53*22028508SToomas Soome 	.dv_print = vdisk_print,
54*22028508SToomas Soome 	.dv_cleanup = NULL
55*22028508SToomas Soome };
56*22028508SToomas Soome 
57*22028508SToomas Soome typedef STAILQ_HEAD(vdisk_info_list, vdisk_info) vdisk_info_list_t;
58*22028508SToomas Soome 
59*22028508SToomas Soome typedef struct vdisk_info
60*22028508SToomas Soome {
61*22028508SToomas Soome 	STAILQ_ENTRY(vdisk_info)	vdisk_link; /* link in device list */
62*22028508SToomas Soome 	char			*vdisk_path;
63*22028508SToomas Soome 	int			vdisk_unit;
64*22028508SToomas Soome 	int			vdisk_fd;
65*22028508SToomas Soome 	uint64_t		vdisk_size;	/* size in bytes */
66*22028508SToomas Soome 	uint32_t		vdisk_sectorsz;
67*22028508SToomas Soome 	uint32_t		vdisk_open;	/* reference counter */
68*22028508SToomas Soome } vdisk_info_t;
69*22028508SToomas Soome 
70*22028508SToomas Soome static vdisk_info_list_t vdisk_list;	/* list of mapped vdisks. */
71*22028508SToomas Soome 
72*22028508SToomas Soome static vdisk_info_t *
vdisk_get_info(struct devdesc * dev)73*22028508SToomas Soome vdisk_get_info(struct devdesc *dev)
74*22028508SToomas Soome {
75*22028508SToomas Soome 	vdisk_info_t *vd;
76*22028508SToomas Soome 
77*22028508SToomas Soome 	STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) {
78*22028508SToomas Soome 		if (vd->vdisk_unit == dev->d_unit)
79*22028508SToomas Soome 			return (vd);
80*22028508SToomas Soome 	}
81*22028508SToomas Soome 	return (vd);
82*22028508SToomas Soome }
83*22028508SToomas Soome 
84*22028508SToomas Soome COMMAND_SET(map_vdisk, "map-vdisk", "map file as virtual disk", command_mapvd);
85*22028508SToomas Soome 
86*22028508SToomas Soome static int
command_mapvd(int argc,char * argv[])87*22028508SToomas Soome command_mapvd(int argc, char *argv[])
88*22028508SToomas Soome {
89*22028508SToomas Soome 	vdisk_info_t *vd, *p;
90*22028508SToomas Soome 	struct stat sb;
91*22028508SToomas Soome 
92*22028508SToomas Soome 	if (argc != 2) {
93*22028508SToomas Soome 		printf("usage: %s filename\n", argv[0]);
94*22028508SToomas Soome 		return (CMD_ERROR);
95*22028508SToomas Soome 	}
96*22028508SToomas Soome 
97*22028508SToomas Soome 	STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) {
98*22028508SToomas Soome 		if (strcmp(vd->vdisk_path, argv[1]) == 0) {
99*22028508SToomas Soome 			printf("%s: file %s is already mapped as %s%d\n",
100*22028508SToomas Soome 			    argv[0], argv[1], vdisk_dev.dv_name,
101*22028508SToomas Soome 			    vd->vdisk_unit);
102*22028508SToomas Soome 			return (CMD_ERROR);
103*22028508SToomas Soome 		}
104*22028508SToomas Soome 	}
105*22028508SToomas Soome 
106*22028508SToomas Soome 	if (stat(argv[1], &sb) < 0) {
107*22028508SToomas Soome 		/*
108*22028508SToomas Soome 		 * ENOSYS is really ENOENT because we did try to walk
109*22028508SToomas Soome 		 * through devsw list to try to open this file.
110*22028508SToomas Soome 		 */
111*22028508SToomas Soome 		if (errno == ENOSYS)
112*22028508SToomas Soome 			errno = ENOENT;
113*22028508SToomas Soome 
114*22028508SToomas Soome 		printf("%s: stat failed: %s\n", argv[0], strerror(errno));
115*22028508SToomas Soome 		return (CMD_ERROR);
116*22028508SToomas Soome 	}
117*22028508SToomas Soome 
118*22028508SToomas Soome 	/*
119*22028508SToomas Soome 	 * Avoid mapping small files.
120*22028508SToomas Soome 	 */
121*22028508SToomas Soome 	if (sb.st_size < 1024 * 1024) {
122*22028508SToomas Soome 		printf("%s: file %s is too small.\n", argv[0], argv[1]);
123*22028508SToomas Soome 		return (CMD_ERROR);
124*22028508SToomas Soome 	}
125*22028508SToomas Soome 
126*22028508SToomas Soome 	vd = calloc(1, sizeof (*vd));
127*22028508SToomas Soome 	if (vd == NULL) {
128*22028508SToomas Soome 		printf("%s: out of memory\n", argv[0]);
129*22028508SToomas Soome 		return (CMD_ERROR);
130*22028508SToomas Soome 	}
131*22028508SToomas Soome 	vd->vdisk_path = strdup(argv[1]);
132*22028508SToomas Soome 	if (vd->vdisk_path == NULL) {
133*22028508SToomas Soome 		free(vd);
134*22028508SToomas Soome 		printf("%s: out of memory\n", argv[0]);
135*22028508SToomas Soome 		return (CMD_ERROR);
136*22028508SToomas Soome 	}
137*22028508SToomas Soome 	vd->vdisk_fd = open(vd->vdisk_path, O_RDONLY);
138*22028508SToomas Soome 	if (vd->vdisk_fd < 0) {
139*22028508SToomas Soome 		printf("%s: open failed: %s\n", argv[0], strerror(errno));
140*22028508SToomas Soome 		free(vd->vdisk_path);
141*22028508SToomas Soome 		free(vd);
142*22028508SToomas Soome 		return (CMD_ERROR);
143*22028508SToomas Soome 	}
144*22028508SToomas Soome 
145*22028508SToomas Soome 	vd->vdisk_size = sb.st_size;
146*22028508SToomas Soome 	vd->vdisk_sectorsz = DEV_BSIZE;
147*22028508SToomas Soome 	STAILQ_FOREACH(p, &vdisk_list, vdisk_link) {
148*22028508SToomas Soome 		vdisk_info_t *n;
149*22028508SToomas Soome 		if (p->vdisk_unit == vd->vdisk_unit) {
150*22028508SToomas Soome 			vd->vdisk_unit++;
151*22028508SToomas Soome 			continue;
152*22028508SToomas Soome 		}
153*22028508SToomas Soome 		n = STAILQ_NEXT(p, vdisk_link);
154*22028508SToomas Soome 		if (p->vdisk_unit < vd->vdisk_unit) {
155*22028508SToomas Soome 			if (n == NULL) {
156*22028508SToomas Soome 				/* p is last elem */
157*22028508SToomas Soome 				STAILQ_INSERT_TAIL(&vdisk_list, vd, vdisk_link);
158*22028508SToomas Soome 				break;
159*22028508SToomas Soome 			}
160*22028508SToomas Soome 			if (n->vdisk_unit > vd->vdisk_unit) {
161*22028508SToomas Soome 				/* p < vd < n */
162*22028508SToomas Soome 				STAILQ_INSERT_AFTER(&vdisk_list, p, vd,
163*22028508SToomas Soome 				    vdisk_link);
164*22028508SToomas Soome 				break;
165*22028508SToomas Soome 			}
166*22028508SToomas Soome 			/* else n < vd or n == vd */
167*22028508SToomas Soome 			vd->vdisk_unit++;
168*22028508SToomas Soome 			continue;
169*22028508SToomas Soome 		}
170*22028508SToomas Soome 		/* p > vd only if p is the first element */
171*22028508SToomas Soome 		STAILQ_INSERT_HEAD(&vdisk_list, vd, vdisk_link);
172*22028508SToomas Soome 		break;
173*22028508SToomas Soome 	}
174*22028508SToomas Soome 
175*22028508SToomas Soome 	/* if the list was empty or contiguous */
176*22028508SToomas Soome 	if (p == NULL)
177*22028508SToomas Soome 		STAILQ_INSERT_TAIL(&vdisk_list, vd, vdisk_link);
178*22028508SToomas Soome 
179*22028508SToomas Soome 	printf("%s: file %s is mapped as %s%d\n", argv[0], vd->vdisk_path,
180*22028508SToomas Soome 	    vdisk_dev.dv_name, vd->vdisk_unit);
181*22028508SToomas Soome 	return (CMD_OK);
182*22028508SToomas Soome }
183*22028508SToomas Soome 
184*22028508SToomas Soome COMMAND_SET(unmap_vdisk, "unmap-vdisk", "unmap virtual disk", command_unmapvd);
185*22028508SToomas Soome 
186*22028508SToomas Soome /*
187*22028508SToomas Soome  * unmap-vdisk vdiskX
188*22028508SToomas Soome  */
189*22028508SToomas Soome static int
command_unmapvd(int argc,char * argv[])190*22028508SToomas Soome command_unmapvd(int argc, char *argv[])
191*22028508SToomas Soome {
192*22028508SToomas Soome 	size_t len;
193*22028508SToomas Soome 	vdisk_info_t *vd;
194*22028508SToomas Soome 	long unit;
195*22028508SToomas Soome 	char *end;
196*22028508SToomas Soome 
197*22028508SToomas Soome 	if (argc != 2) {
198*22028508SToomas Soome 		printf("usage: %s %sN\n", argv[0], vdisk_dev.dv_name);
199*22028508SToomas Soome 		return (CMD_ERROR);
200*22028508SToomas Soome 	}
201*22028508SToomas Soome 
202*22028508SToomas Soome 	len = strlen(vdisk_dev.dv_name);
203*22028508SToomas Soome 	if (strncmp(vdisk_dev.dv_name, argv[1], len) != 0) {
204*22028508SToomas Soome 		printf("%s: unknown device %s\n", argv[0], argv[1]);
205*22028508SToomas Soome 		return (CMD_ERROR);
206*22028508SToomas Soome 	}
207*22028508SToomas Soome 	errno = 0;
208*22028508SToomas Soome 	unit = strtol(argv[1] + len, &end, 10);
209*22028508SToomas Soome 	if (errno != 0 || (*end != '\0' && strcmp(end, ":") != 0)) {
210*22028508SToomas Soome 		printf("%s: unknown device %s\n", argv[0], argv[1]);
211*22028508SToomas Soome 		return (CMD_ERROR);
212*22028508SToomas Soome 	}
213*22028508SToomas Soome 
214*22028508SToomas Soome 	STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) {
215*22028508SToomas Soome 		if (vd->vdisk_unit == unit)
216*22028508SToomas Soome 			break;
217*22028508SToomas Soome 	}
218*22028508SToomas Soome 
219*22028508SToomas Soome 	if (vd == NULL) {
220*22028508SToomas Soome 		printf("%s: unknown device %s\n", argv[0], argv[1]);
221*22028508SToomas Soome 		return (CMD_ERROR);
222*22028508SToomas Soome 	}
223*22028508SToomas Soome 
224*22028508SToomas Soome 	if (vd->vdisk_open != 0) {
225*22028508SToomas Soome 		printf("%s: %s is in use, unable to unmap.\n",
226*22028508SToomas Soome 		    argv[0], argv[1]);
227*22028508SToomas Soome 		return (CMD_ERROR);
228*22028508SToomas Soome 	}
229*22028508SToomas Soome 
230*22028508SToomas Soome 	STAILQ_REMOVE(&vdisk_list, vd, vdisk_info, vdisk_link);
231*22028508SToomas Soome 	(void) close(vd->vdisk_fd);
232*22028508SToomas Soome 	printf("%s (%s) unmapped\n", argv[1], vd->vdisk_path);
233*22028508SToomas Soome 	free(vd->vdisk_path);
234*22028508SToomas Soome 	free(vd);
235*22028508SToomas Soome 
236*22028508SToomas Soome 	return (CMD_OK);
237*22028508SToomas Soome }
238*22028508SToomas Soome 
239*22028508SToomas Soome static int
vdisk_init(void)240*22028508SToomas Soome vdisk_init(void)
241*22028508SToomas Soome {
242*22028508SToomas Soome 	STAILQ_INIT(&vdisk_list);
243*22028508SToomas Soome 	return (0);
244*22028508SToomas Soome }
245*22028508SToomas Soome 
246*22028508SToomas Soome static int
vdisk_strategy(void * devdata,int rw,daddr_t blk,size_t size,char * buf,size_t * rsize)247*22028508SToomas Soome vdisk_strategy(void *devdata, int rw, daddr_t blk, size_t size,
248*22028508SToomas Soome     char *buf, size_t *rsize)
249*22028508SToomas Soome {
250*22028508SToomas Soome 	struct disk_devdesc *dev;
251*22028508SToomas Soome 	vdisk_info_t *vd;
252*22028508SToomas Soome 	ssize_t rv;
253*22028508SToomas Soome 
254*22028508SToomas Soome 	dev = devdata;
255*22028508SToomas Soome 	if (dev == NULL)
256*22028508SToomas Soome 		return (EINVAL);
257*22028508SToomas Soome 	vd = vdisk_get_info((struct devdesc *)dev);
258*22028508SToomas Soome 	if (vd == NULL)
259*22028508SToomas Soome 		return (EINVAL);
260*22028508SToomas Soome 
261*22028508SToomas Soome 	if (size == 0 || (size % 512) != 0)
262*22028508SToomas Soome 		return (EIO);
263*22028508SToomas Soome 
264*22028508SToomas Soome 	if (dev->dd.d_dev->dv_type == DEVT_DISK) {
265*22028508SToomas Soome 		daddr_t offset;
266*22028508SToomas Soome 
267*22028508SToomas Soome 		offset = dev->d_offset * vd->vdisk_sectorsz;
268*22028508SToomas Soome 		offset /= 512;
269*22028508SToomas Soome 		blk += offset;
270*22028508SToomas Soome 	}
271*22028508SToomas Soome 	if (lseek(vd->vdisk_fd, blk << 9, SEEK_SET) == -1)
272*22028508SToomas Soome 		return (EIO);
273*22028508SToomas Soome 
274*22028508SToomas Soome 	errno = 0;
275*22028508SToomas Soome 	switch (rw & F_MASK) {
276*22028508SToomas Soome 	case F_READ:
277*22028508SToomas Soome 		rv = read(vd->vdisk_fd, buf, size);
278*22028508SToomas Soome 		break;
279*22028508SToomas Soome 	case F_WRITE:
280*22028508SToomas Soome 		rv = write(vd->vdisk_fd, buf, size);
281*22028508SToomas Soome 		break;
282*22028508SToomas Soome 	default:
283*22028508SToomas Soome 		return (ENOSYS);
284*22028508SToomas Soome 	}
285*22028508SToomas Soome 
286*22028508SToomas Soome 	if (errno == 0 && rsize != NULL) {
287*22028508SToomas Soome 		*rsize = rv;
288*22028508SToomas Soome 	}
289*22028508SToomas Soome 	return (errno);
290*22028508SToomas Soome }
291*22028508SToomas Soome 
292*22028508SToomas Soome static int
vdisk_open(struct open_file * f,...)293*22028508SToomas Soome vdisk_open(struct open_file *f, ...)
294*22028508SToomas Soome {
295*22028508SToomas Soome 	va_list args;
296*22028508SToomas Soome 	struct disk_devdesc *dev;
297*22028508SToomas Soome 	vdisk_info_t *vd;
298*22028508SToomas Soome 	int rc = 0;
299*22028508SToomas Soome 
300*22028508SToomas Soome 	va_start(args, f);
301*22028508SToomas Soome 	dev = va_arg(args, struct disk_devdesc *);
302*22028508SToomas Soome 	va_end(args);
303*22028508SToomas Soome 	if (dev == NULL)
304*22028508SToomas Soome 		return (EINVAL);
305*22028508SToomas Soome 	vd = vdisk_get_info((struct devdesc *)dev);
306*22028508SToomas Soome 	if (vd == NULL)
307*22028508SToomas Soome 		return (EINVAL);
308*22028508SToomas Soome 
309*22028508SToomas Soome 	if (dev->dd.d_dev->dv_type == DEVT_DISK) {
310*22028508SToomas Soome 		rc = disk_open(dev, vd->vdisk_size, vd->vdisk_sectorsz);
311*22028508SToomas Soome 	}
312*22028508SToomas Soome 	if (rc == 0)
313*22028508SToomas Soome 		vd->vdisk_open++;
314*22028508SToomas Soome 	return (rc);
315*22028508SToomas Soome }
316*22028508SToomas Soome 
317*22028508SToomas Soome static int
vdisk_close(struct open_file * f)318*22028508SToomas Soome vdisk_close(struct open_file *f)
319*22028508SToomas Soome {
320*22028508SToomas Soome 	struct disk_devdesc *dev;
321*22028508SToomas Soome 	vdisk_info_t *vd;
322*22028508SToomas Soome 
323*22028508SToomas Soome 	dev = (struct disk_devdesc *)(f->f_devdata);
324*22028508SToomas Soome 	if (dev == NULL)
325*22028508SToomas Soome 		return (EINVAL);
326*22028508SToomas Soome 	vd = vdisk_get_info((struct devdesc *)dev);
327*22028508SToomas Soome 	if (vd == NULL)
328*22028508SToomas Soome 		return (EINVAL);
329*22028508SToomas Soome 
330*22028508SToomas Soome 	vd->vdisk_open--;
331*22028508SToomas Soome 	if (dev->dd.d_dev->dv_type == DEVT_DISK)
332*22028508SToomas Soome 		return (disk_close(dev));
333*22028508SToomas Soome 	return (0);
334*22028508SToomas Soome }
335*22028508SToomas Soome 
336*22028508SToomas Soome static int
vdisk_ioctl(struct open_file * f,ulong_t cmd,void * data)337*22028508SToomas Soome vdisk_ioctl(struct open_file *f, ulong_t cmd, void *data)
338*22028508SToomas Soome {
339*22028508SToomas Soome 	struct disk_devdesc *dev;
340*22028508SToomas Soome 	vdisk_info_t *vd;
341*22028508SToomas Soome 	int rc;
342*22028508SToomas Soome 
343*22028508SToomas Soome 	dev = (struct disk_devdesc *)(f->f_devdata);
344*22028508SToomas Soome 	if (dev == NULL)
345*22028508SToomas Soome 		return (EINVAL);
346*22028508SToomas Soome 	vd = vdisk_get_info((struct devdesc *)dev);
347*22028508SToomas Soome 	if (vd == NULL)
348*22028508SToomas Soome 		return (EINVAL);
349*22028508SToomas Soome 
350*22028508SToomas Soome 	if (dev->dd.d_dev->dv_type == DEVT_DISK) {
351*22028508SToomas Soome 		rc = disk_ioctl(dev, cmd, data);
352*22028508SToomas Soome 		if (rc != ENOTTY)
353*22028508SToomas Soome 			return (rc);
354*22028508SToomas Soome 	}
355*22028508SToomas Soome 
356*22028508SToomas Soome 	switch (cmd) {
357*22028508SToomas Soome 	case DIOCGSECTORSIZE:
358*22028508SToomas Soome 		*(uint_t *)data = vd->vdisk_sectorsz;
359*22028508SToomas Soome 		break;
360*22028508SToomas Soome 	case DIOCGMEDIASIZE:
361*22028508SToomas Soome 		*(uint64_t *)data = vd->vdisk_size;
362*22028508SToomas Soome 		break;
363*22028508SToomas Soome 	default:
364*22028508SToomas Soome 		return (ENOTTY);
365*22028508SToomas Soome 	}
366*22028508SToomas Soome 	return (0);
367*22028508SToomas Soome }
368*22028508SToomas Soome 
369*22028508SToomas Soome static int
vdisk_print(int verbose)370*22028508SToomas Soome vdisk_print(int verbose)
371*22028508SToomas Soome {
372*22028508SToomas Soome 	int ret = 0;
373*22028508SToomas Soome 	vdisk_info_t *vd;
374*22028508SToomas Soome 	char line[80];
375*22028508SToomas Soome 
376*22028508SToomas Soome 	if (STAILQ_EMPTY(&vdisk_list))
377*22028508SToomas Soome 		return (ret);
378*22028508SToomas Soome 
379*22028508SToomas Soome 	printf("%s devices:", vdisk_dev.dv_name);
380*22028508SToomas Soome 	if ((ret = pager_output("\n")) != 0)
381*22028508SToomas Soome 		return (ret);
382*22028508SToomas Soome 
383*22028508SToomas Soome 	STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) {
384*22028508SToomas Soome 		struct disk_devdesc vd_dev;
385*22028508SToomas Soome 
386*22028508SToomas Soome 		if (verbose) {
387*22028508SToomas Soome 			printf("  %s", vd->vdisk_path);
388*22028508SToomas Soome 			if ((ret = pager_output("\n")) != 0)
389*22028508SToomas Soome 				break;
390*22028508SToomas Soome 		}
391*22028508SToomas Soome 		snprintf(line, sizeof (line),
392*22028508SToomas Soome 		    "    %s%d", vdisk_dev.dv_name, vd->vdisk_unit);
393*22028508SToomas Soome 		printf("%s:    %" PRIu64 " X %u blocks", line,
394*22028508SToomas Soome 		    vd->vdisk_size / vd->vdisk_sectorsz,
395*22028508SToomas Soome 		    vd->vdisk_sectorsz);
396*22028508SToomas Soome 		if ((ret = pager_output("\n")) != 0)
397*22028508SToomas Soome 			break;
398*22028508SToomas Soome 
399*22028508SToomas Soome 		vd_dev.dd.d_dev = &vdisk_dev;
400*22028508SToomas Soome 		vd_dev.dd.d_unit = vd->vdisk_unit;
401*22028508SToomas Soome 		vd_dev.d_slice = -1;
402*22028508SToomas Soome 		vd_dev.d_partition = -1;
403*22028508SToomas Soome 
404*22028508SToomas Soome 		ret = disk_open(&vd_dev, vd->vdisk_size, vd->vdisk_sectorsz);
405*22028508SToomas Soome 		if (ret == 0) {
406*22028508SToomas Soome 			ret = disk_print(&vd_dev, line, verbose);
407*22028508SToomas Soome 			disk_close(&vd_dev);
408*22028508SToomas Soome 			if (ret != 0)
409*22028508SToomas Soome 				break;
410*22028508SToomas Soome 		} else {
411*22028508SToomas Soome 			ret = 0;
412*22028508SToomas Soome 		}
413*22028508SToomas Soome 	}
414*22028508SToomas Soome 
415*22028508SToomas Soome 	return (ret);
416*22028508SToomas Soome }
417