Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/libofw/ofw_disk.c
34677 views
1
/*-
2
* Copyright (C) 2000 Benno Rice.
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 Benno Rice ``AS IS'' AND ANY EXPRESS OR
15
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
*/
25
26
/*
27
* Disk I/O routines using Open Firmware
28
*/
29
30
#include <sys/param.h>
31
#include <sys/stdarg.h>
32
33
#include <netinet/in.h>
34
35
#include <stand.h>
36
#include <sys/disk.h>
37
38
#include "disk.h"
39
#include "libofw.h"
40
41
static int ofwd_init(void);
42
static int ofwd_strategy(void *devdata, int flag, daddr_t dblk,
43
size_t size, char *buf, size_t *rsize);
44
static int ofwd_open(struct open_file *f, ...);
45
static int ofwd_close(struct open_file *f);
46
static int ofwd_ioctl(struct open_file *f, u_long cmd, void *data);
47
static int ofwd_print(int verbose);
48
static char * ofwd_fmtdev(struct devdesc *);
49
static int ofwd_parsedev(struct devdesc **, const char *, const char **);
50
static bool ofwd_match(struct devsw *, const char *);
51
52
struct devsw ofwdisk = {
53
.dv_name = "block",
54
.dv_type = DEVT_OFDISK,
55
.dv_init = ofwd_init,
56
.dv_strategy = ofwd_strategy,
57
.dv_open = ofwd_open,
58
.dv_close = ofwd_close,
59
.dv_ioctl = ofwd_ioctl,
60
.dv_print = ofwd_print,
61
.dv_cleanup = nullsys,
62
.dv_match = ofwd_match,
63
.dv_fmtdev = ofwd_fmtdev,
64
.dv_parsedev = ofwd_parsedev,
65
};
66
67
/*
68
* We're not guaranteed to be able to open a device more than once and there
69
* is no OFW standard method to determine whether a device is already opened.
70
* Opening a device multiple times simultaneously happens to work with most
71
* OFW block device drivers but triggers a trap with at least the driver for
72
* the on-board controllers of Sun Fire V100 and Ultra 1. Upper layers and MI
73
* code expect to be able to open a device more than once however. Given that
74
* different partitions of the same device might be opened at the same time as
75
* done by ZFS, we can't generally just keep track of the opened devices and
76
* reuse the instance handle when asked to open an already opened device. So
77
* the best we can do is to cache the lastly used device path and close and
78
* open devices in ofwd_strategy() as needed.
79
*/
80
static struct ofw_devdesc *kdp;
81
82
static int
83
ofwd_init(void)
84
{
85
86
return (0);
87
}
88
89
static int
90
ofwd_strategy(void *devdata, int flag __unused, daddr_t dblk, size_t size,
91
char *buf, size_t *rsize)
92
{
93
struct ofw_devdesc *dp = (struct ofw_devdesc *)devdata;
94
daddr_t pos;
95
int n;
96
97
if (dp != kdp) {
98
if (kdp != NULL) {
99
#if !defined(__powerpc__)
100
OF_close(kdp->d_handle);
101
#endif
102
kdp = NULL;
103
}
104
if ((dp->d_handle = OF_open(dp->d_path)) == -1)
105
return (ENOENT);
106
kdp = dp;
107
}
108
109
pos = dblk * 512;
110
do {
111
if (OF_seek(dp->d_handle, pos) < 0)
112
return (EIO);
113
n = OF_read(dp->d_handle, buf, size);
114
if (n < 0 && n != -2)
115
return (EIO);
116
} while (n == -2);
117
*rsize = size;
118
return (0);
119
}
120
121
static int
122
ofwd_open(struct open_file *f, ...)
123
{
124
struct ofw_devdesc *dp;
125
va_list vl;
126
127
va_start(vl, f);
128
dp = va_arg(vl, struct ofw_devdesc *);
129
va_end(vl);
130
131
if (dp != kdp) {
132
if (kdp != NULL) {
133
OF_close(kdp->d_handle);
134
kdp = NULL;
135
}
136
if ((dp->d_handle = OF_open(dp->d_path)) == -1) {
137
printf("%s: Could not open %s\n", __func__,
138
dp->d_path);
139
return (ENOENT);
140
}
141
kdp = dp;
142
}
143
return (0);
144
}
145
146
static int
147
ofwd_close(struct open_file *f)
148
{
149
struct ofw_devdesc *dev = f->f_devdata;
150
151
if (dev == kdp) {
152
#if !defined(__powerpc__)
153
OF_close(dev->d_handle);
154
#endif
155
kdp = NULL;
156
}
157
return (0);
158
}
159
160
static int
161
ofwd_ioctl(struct open_file *f, u_long cmd, void *data)
162
{
163
struct ofw_devdesc *dev = f->f_devdata;
164
int block_size;
165
unsigned int n;
166
167
switch (cmd) {
168
case DIOCGSECTORSIZE:
169
block_size = OF_block_size(dev->d_handle);
170
*(u_int *)data = block_size;
171
break;
172
case DIOCGMEDIASIZE:
173
block_size = OF_block_size(dev->d_handle);
174
n = OF_blocks(dev->d_handle);
175
*(uint64_t *)data = ((uint64_t)n * block_size);
176
break;
177
default:
178
return (ENOTTY);
179
}
180
return (0);
181
}
182
183
static int
184
ofwd_print(int verbose __unused)
185
{
186
uintmax_t block_size, n;
187
int ret;
188
char line[80];
189
190
/*
191
* We don't have a list of devices since we don't parse the whole OFW
192
* tree to find them. Instead, if we have an open device print info
193
* about it. Otherwise say we can't. Makes lsdev nicer.
194
*/
195
if ((ret = pager_output("block devices:\n")) != 0)
196
return (ret);
197
if (kdp != NULL) {
198
block_size = OF_block_size(kdp->d_handle);
199
n = OF_blocks(kdp->d_handle);
200
snprintf(line, sizeof(line),
201
" %s: OFW block device (%ju X %ju): %ju bytes\n",
202
kdp->d_path, n, block_size, n * block_size);
203
if ((ret = pager_output(line)) != 0)
204
return (ret);
205
} else {
206
if ((ret = pager_output(" none are open, so no info\n")) != 0)
207
return (ret);
208
}
209
210
return (0);
211
}
212
213
214
static bool
215
ofwd_match(struct devsw *devsw, const char *devspec)
216
{
217
const char *path;
218
219
return (ofw_path_to_handle(devspec, devsw->dv_name, &path) != -1);
220
}
221
222
static char *
223
ofwd_fmtdev(struct devdesc *idev)
224
{
225
struct ofw_devdesc *dev = (struct ofw_devdesc *)idev;
226
227
return (dev->d_path);
228
}
229
230
static int
231
ofwd_parsedev(struct devdesc **dev, const char *devspec, const char **path)
232
{
233
return (ofw_common_parsedev(dev, devspec, path, ofwdisk.dv_name));
234
}
235
236