xref: /titanic_52/usr/src/boot/sys/boot/userboot/userboot/userboot_disk.c (revision a5a5c3b743b38bcec1dcdc221fc56e3c2272e79f)
1 /*-
2  * Copyright (c) 2011 Google, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 /*
31  * Userboot disk image handling.
32  */
33 
34 #include <sys/disk.h>
35 #include <stand.h>
36 #include <stdarg.h>
37 #include <bootstrap.h>
38 
39 #include "disk.h"
40 #include "libuserboot.h"
41 
42 struct userdisk_info {
43 	uint64_t	mediasize;
44 	uint16_t	sectorsize;
45 };
46 
47 int userboot_disk_maxunit = 0;
48 
49 static int userdisk_maxunit = 0;
50 static struct userdisk_info	*ud_info;
51 
52 static int	userdisk_init(void);
53 static void	userdisk_cleanup(void);
54 static int	userdisk_strategy(void *devdata, int flag, daddr_t dblk,
55 		    size_t size, char *buf, size_t *rsize);
56 static int	userdisk_open(struct open_file *f, ...);
57 static int	userdisk_close(struct open_file *f);
58 static int	userdisk_ioctl(struct open_file *f, u_long cmd, void *data);
59 static int	userdisk_print(int verbose);
60 
61 struct devsw userboot_disk = {
62 	"disk",
63 	DEVT_DISK,
64 	userdisk_init,
65 	userdisk_strategy,
66 	userdisk_open,
67 	userdisk_close,
68 	userdisk_ioctl,
69 	userdisk_print,
70 	userdisk_cleanup
71 };
72 
73 /*
74  * Initialize userdisk_info structure for each disk.
75  */
76 static int
77 userdisk_init(void)
78 {
79 	off_t mediasize;
80 	u_int sectorsize;
81 	int i;
82 
83 	userdisk_maxunit = userboot_disk_maxunit;
84 	if (userdisk_maxunit > 0) {
85 		ud_info = malloc(sizeof(*ud_info) * userdisk_maxunit);
86 		if (ud_info == NULL)
87 			return (ENOMEM);
88 		for (i = 0; i < userdisk_maxunit; i++) {
89 			if (CALLBACK(diskioctl, i, DIOCGSECTORSIZE,
90 			    &sectorsize) != 0 || CALLBACK(diskioctl, i,
91 			    DIOCGMEDIASIZE, &mediasize) != 0)
92 				return (ENXIO);
93 			ud_info[i].mediasize = mediasize;
94 			ud_info[i].sectorsize = sectorsize;
95 		}
96 	}
97 
98 	return(0);
99 }
100 
101 static void
102 userdisk_cleanup(void)
103 {
104 
105 	if (userdisk_maxunit > 0)
106 		free(ud_info);
107 	disk_cleanup(&userboot_disk);
108 }
109 
110 /*
111  * Print information about disks
112  */
113 static int
114 userdisk_print(int verbose)
115 {
116 	struct disk_devdesc dev;
117 	char line[80];
118 	int i;
119 
120 	if (userdisk_maxunit == 0)
121 		return (0);
122 
123 	printf("%s devices:", userboot_disk.dv_name);
124 	if ((ret = pager_output("\n")) != 0)
125 		return (ret);
126 
127 	for (i = 0; i < userdisk_maxunit; i++) {
128 		sprintf(line, "    disk%d:   Guest drive image\n", i);
129 		pager_output(line);
130 		dev.d_dev = &userboot_disk;
131 		dev.d_unit = i;
132 		dev.d_slice = -1;
133 		dev.d_partition = -1;
134 		if (disk_open(&dev, ud_info[i].mediasize,
135 		    ud_info[i].sectorsize) == 0) {
136 			sprintf(line, "    disk%d", i);
137 			disk_print(&dev, line, verbose);
138 			disk_close(&dev);
139 		}
140 	}
141 }
142 
143 /*
144  * Attempt to open the disk described by (dev) for use by (f).
145  */
146 static int
147 userdisk_open(struct open_file *f, ...)
148 {
149 	va_list			ap;
150 	struct disk_devdesc	*dev;
151 
152 	va_start(ap, f);
153 	dev = va_arg(ap, struct disk_devdesc *);
154 	va_end(ap);
155 
156 	if (dev->d_unit < 0 || dev->d_unit >= userdisk_maxunit)
157 		return (EIO);
158 
159 	return (disk_open(dev, ud_info[dev->d_unit].mediasize,
160 	    ud_info[dev->d_unit].sectorsize));
161 }
162 
163 static int
164 userdisk_close(struct open_file *f)
165 {
166 	struct disk_devdesc *dev;
167 
168 	dev = (struct disk_devdesc *)f->f_devdata;
169 	return (disk_close(dev));
170 }
171 
172 static int
173 userdisk_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
174     char *buf, size_t *rsize)
175 {
176 	struct disk_devdesc *dev = devdata;
177 	uint64_t	off;
178 	size_t		resid;
179 	int		rc;
180 
181 	rw &= F_MASK;
182 	if (rw == F_WRITE)
183 		return (EROFS);
184 	if (rw != F_READ)
185 		return (EINVAL);
186 	if (rsize)
187 		*rsize = 0;
188 	off = (dblk + dev->d_offset) * ud_info[dev->d_unit].sectorsize;
189 	rc = CALLBACK(diskread, dev->d_unit, off, buf, size, &resid);
190 	if (rc)
191 		return (rc);
192 	if (rsize)
193 		*rsize = size - resid;
194 	return (0);
195 }
196 
197 static int
198 userdisk_ioctl(struct open_file *f, u_long cmd, void *data)
199 {
200 	struct disk_devdesc *dev;
201 
202 	dev = (struct disk_devdesc *)f->f_devdata;
203 	return (CALLBACK(diskioctl, dev->d_unit, cmd, data));
204 }
205