diskio.c revision 1.1 1 /* $NetBSD: diskio.c,v 1.1 1996/01/07 21:54:16 leo Exp $ */
2
3 /*
4 * Copyright (c) 1995 Waldi Ravens.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Waldi Ravens.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/types.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <stdio.h>
38 #include <xhdi.h>
39 #include "libtos.h"
40 #include "aptck.h"
41 #include "disklabel.h"
42 #include <osbind.h>
43
44 struct pun_info {
45 u_int16_t puns;
46 u_int8_t pun[16];
47 u_int32_t part_start[16];
48 u_int32_t P_cookie;
49 u_int32_t *P_cookptr;
50 u_int16_t P_version;
51 u_int16_t P_max_sector;
52 u_int32_t reserved[16];
53 };
54
55 static char * strbd PROTO((char *, ...));
56 static int setmami PROTO((disk_t *, char *));
57 static int setnames PROTO((disk_t *));
58 static int setsizes PROTO((disk_t *));
59 static int ahdi_compatible PROTO((void));
60
61 disk_t *
62 disk_open(name)
63 char *name;
64 {
65 disk_t *dd;
66
67 dd = xmalloc(sizeof *dd);
68 memset(dd, 0, sizeof *dd);
69
70 if (setmami(dd, name) || setnames(dd) || setsizes(dd)) {
71 disk_close(dd);
72 return(NULL);
73 }
74 return(dd);
75 }
76
77 void
78 disk_close(dd)
79 disk_t *dd;
80 {
81 if (dd) {
82 free(dd->product);
83 free(dd->sname);
84 free(dd->fname);
85 free(dd->roots);
86 free(dd->parts);
87 free(dd);
88 }
89 }
90
91 void *
92 disk_read(dd, start, count)
93 disk_t *dd;
94 u_int start,
95 count;
96 {
97 char *buffer;
98 int bdev;
99 long e;
100
101 buffer = xmalloc(count * dd->bsize);
102
103 e = XHReadWrite(dd->major, dd->minor, 0, start, count, buffer);
104 if (!e)
105 return(buffer);
106 if (e == -32 || (e == -1 && XHGetVersion() == -1)) {
107 if (!ahdi_compatible())
108 fatal(-1, "AHDI 3.0 compatible harddisk driver required");
109 bdev = BIOSDEV(dd->major, dd->minor);
110 if (bdev && !bios_read(buffer, start, count, bdev))
111 return(buffer);
112 }
113
114 free(buffer);
115 return(NULL);
116 }
117
118 int
119 disk_write(dd, start, count, buffer)
120 disk_t *dd;
121 u_int start,
122 count;
123 void *buffer;
124 {
125 int bdev;
126 long e;
127
128 e = XHReadWrite(dd->major, dd->minor, 1, start, count, buffer);
129 if (e == -32 || (e == -1 && XHGetVersion() == -1)) {
130 if (!ahdi_compatible())
131 fatal(-1, "AHDI 3.0 compatible harddisk driver required");
132 bdev = BIOSDEV(dd->major, dd->minor);
133 if (bdev)
134 e = bios_write(buffer, start, count, bdev);
135 }
136
137 return((int)e);
138 }
139
140 static int
141 ahdi_compatible()
142 {
143 static int ahdi_compat;
144
145 if (!ahdi_compat) {
146 long oldsp = Super(0L);
147 struct pun_info *punp = *((struct pun_info **)0x0516);
148 Super(oldsp);
149 if (punp && punp->P_cookie == 0x41484449
150 && punp->P_cookptr == &punp->P_cookie
151 && punp->P_version >= 0x0300)
152 ahdi_compat = 1;
153 }
154 return(ahdi_compat);
155 }
156
157 static int
158 setmami(dd, name)
159 disk_t *dd;
160 char *name;
161 {
162 char *p = name;
163 u_int target, lun;
164 bus_t bus;
165
166 if (*p == 'i') {
167 bus = IDE;
168 if (*++p < '0' || *p > '1') {
169 if (*p)
170 error(-1, "%s: invalid IDE target `%c'", name, *p);
171 else
172 error(-1, "%s: missing IDE target", name);
173 return(-1);
174 }
175 target = *p++ - '0';
176 lun = 0;
177 } else {
178 char *b;
179
180 if (*p == 'a') {
181 bus = ACSI;
182 b = "ACSI";
183 } else if (*p == 's') {
184 bus = SCSI;
185 b = "SCSI";
186 } else {
187 error(-1, "%s: invalid DISK argument", name);
188 return(-1);
189 }
190 if (*++p < '0' || *p > '7') {
191 if (*p)
192 error(-1, "%s: invalid %s target `%c'", name, b, *p);
193 else
194 error(-1, "%s: missing %s target", name, b);
195 return(-1);
196 }
197 target = *p++ - '0';
198
199 if (*p < '0' || *p > '7') {
200 if (*p) {
201 error(-1, "%s: invalid %s lun `%c'", name, b, *p);
202 return(-1);
203 }
204 lun = 0;
205 } else
206 lun = *p++ - '0';
207 }
208 if (*p) {
209 error(-1, "%s: invalid DISK argument", name);
210 return(-1);
211 }
212 dd->major = MAJOR(bus, target, lun);
213 dd->minor = MINOR(bus, target, lun);
214 return(0);
215 }
216
217 static int
218 setnames(dd)
219 disk_t *dd;
220 {
221 char sn[16], us[16], ls[16], *bs;
222 int b, u, l;
223
224 b = BUS(dd->major, dd->minor);
225 u = TARGET(dd->major, dd->minor);
226 l = LUN(dd->major, dd->minor);
227
228 switch (b) {
229 case IDE: bs = "IDE";
230 break;
231 case ACSI: bs = "ACSI";
232 break;
233 case SCSI: bs = "SCSI";
234 break;
235 default: error(-1, "invalid bus no. %d", b);
236 return(-1);
237 }
238
239 if (u < 0 || u > 7 || (b == IDE && u > 1)) {
240 error(-1, "invalid %s target `%d'", bs, u);
241 return(-1);
242 }
243 sprintf(us, " target %d", u);
244
245 if (l < 0 || l > 7 || (b == IDE && l > 0)) {
246 error(-1, "invalid %s lun `%d'", bs, l);
247 return(-1);
248 }
249 if (b == IDE) {
250 sprintf(sn, "i%d", u);
251 ls[0] = '\0';
252 } else {
253 sprintf(sn, "%c%d%d", tolower(*bs), u, l);
254 sprintf(ls, " lun %d", l);
255 }
256
257 dd->fname = strbd(bs, us, ls, NULL);
258 dd->sname = strbd(sn, NULL);
259 return(0);
260 }
261
262 static int
263 setsizes(dd)
264 disk_t *dd;
265 {
266 if (XHGetVersion() != -1) {
267 char *p, prod[1024];
268
269 if (XHInqTarget2(dd->major, dd->minor, &dd->bsize, NULL, prod, sizeof(prod))) {
270 if (XHInqTarget(dd->major, dd->minor, &dd->bsize, NULL, prod)) {
271 error(-1, "%s: device not configured", dd->sname);
272 return(-1);
273 }
274 }
275 p = strrchr(prod, '\0');
276 while (isspace(*--p))
277 *p = '\0';
278 dd->product = strbd(prod, NULL);
279 if (!XHGetCapacity(dd->major, dd->minor, &dd->msize, &dd->bsize))
280 return(0);
281 } else {
282 dd->product = strbd("unknown", NULL);
283 dd->bsize = AHDI_BSIZE; /* XXX */
284 }
285
286 /* Trial&error search for last sector on medium */
287 {
288 u_int u, l, m;
289 void *p, (*oldvec)();
290
291 /* turn off etv_critic handler */
292 oldvec = Setexc(257, bios_critic);
293
294 u = (u_int)-2; l = 0;
295 while (u != l) {
296 m = l + ((u - l + 1) / 2);
297 p = disk_read(dd, m, 1);
298 free(p);
299 if (p == NULL)
300 u = m - 1;
301 else
302 l = m;
303 }
304
305 /* turn on etv_critic handler */
306 (void)Setexc(257, oldvec);
307
308 if (l) {
309 dd->msize = l + 1;
310 return(0);
311 }
312 error(-1, "%s: device not configured", dd->sname);
313 return(-1);
314 }
315 }
316
317 char *
318 strbd(string1)
319 char *string1;
320 {
321 char *p, *result;
322 size_t length = 1;
323 va_list ap;
324
325 va_start(ap, string1);
326 for (p = string1; p; p = va_arg(ap, char *))
327 length += strlen(p);
328 va_end(ap);
329
330 *(result = xmalloc(length)) = '\0';
331
332 va_start(ap, string1);
333 for (p = string1; p; p = va_arg(ap, char *))
334 strcat(result, p);
335 va_end(ap);
336
337 return(result);
338 }
339