diskio.c revision 1.1.2.2 1 /* $NetBSD: diskio.c,v 1.1.2.2 2002/02/28 04:08:33 nathanw 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 "diskio.h"
41 #include "ahdilbl.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 if (dd->xtra_info != NULL)
86 free(dd->xtra_info);
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 (void)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,
193 b, *p);
194 else
195 error(-1, "%s: missing %s target", name, b);
196 return(-1);
197 }
198 target = *p++ - '0';
199
200 if (*p < '0' || *p > '7') {
201 if (*p) {
202 error(-1, "%s: invalid %s lun `%c'", name,
203 b, *p);
204 return(-1);
205 }
206 lun = 0;
207 } else
208 lun = *p++ - '0';
209 }
210 if (*p) {
211 error(-1, "%s: invalid DISK argument", name);
212 return(-1);
213 }
214 dd->major = MAJOR(bus, target, lun);
215 dd->minor = MINOR(bus, target, lun);
216 return(0);
217 }
218
219 static int
220 setnames(dd)
221 disk_t *dd;
222 {
223 char sn[16], us[16], ls[16], *bs;
224 int b, u, l;
225
226 b = BUS(dd->major, dd->minor);
227 u = TARGET(dd->major, dd->minor);
228 l = LUN(dd->major, dd->minor);
229
230 switch (b) {
231 case IDE: bs = "IDE";
232 break;
233 case ACSI: bs = "ACSI";
234 break;
235 case SCSI: bs = "SCSI";
236 break;
237 default: error(-1, "invalid bus no. %d", b);
238 return(-1);
239 }
240
241 if (u < 0 || u > 7 || (b == IDE && u > 1)) {
242 error(-1, "invalid %s target `%d'", bs, u);
243 return(-1);
244 }
245 sprintf(us, " target %d", u);
246
247 if (l < 0 || l > 7 || (b == IDE && l > 0)) {
248 error(-1, "invalid %s lun `%d'", bs, l);
249 return(-1);
250 }
251 if (b == IDE) {
252 sprintf(sn, "i%d", u);
253 ls[0] = '\0';
254 } else {
255 sprintf(sn, "%c%d%d", tolower(*bs), u, l);
256 sprintf(ls, " lun %d", l);
257 }
258
259 dd->fname = strbd(bs, us, ls, NULL);
260 dd->sname = strbd(sn, NULL);
261 return(0);
262 }
263
264 static int
265 setsizes(dd)
266 disk_t *dd;
267 {
268 if (XHGetVersion() != -1) {
269 char *p, prod[1024];
270
271 if (XHInqTarget2(dd->major, dd->minor, &dd->bsize, NULL, prod,
272 sizeof(prod))) {
273 if (XHInqTarget(dd->major, dd->minor, &dd->bsize, NULL, prod)) {
274 error(-1, "%s: device not configured", dd->sname);
275 return(-1);
276 }
277 }
278 p = strrchr(prod, '\0');
279 while (isspace(*--p))
280 *p = '\0';
281 dd->product = strbd(prod, NULL);
282 if (!XHGetCapacity(dd->major, dd->minor, &dd->msize, &dd->bsize))
283 return(0);
284 } else {
285 dd->product = strbd("unknown", NULL);
286 dd->bsize = AHDI_BSIZE; /* XXX */
287 }
288
289 /* Trial&error search for last sector on medium */
290 {
291 u_int u, l, m;
292 void *p, (*oldvec)();
293
294 /* turn off etv_critic handler */
295 oldvec = Setexc(257, bios_critic);
296
297 u = (u_int)-2; l = 0;
298 while (u != l) {
299 m = l + ((u - l + 1) / 2);
300 p = disk_read(dd, m, 1);
301 free(p);
302 if (p == NULL)
303 u = m - 1;
304 else
305 l = m;
306 }
307
308 /* turn on etv_critic handler */
309 (void)Setexc(257, oldvec);
310
311 if (l) {
312 dd->msize = l + 1;
313 return(0);
314 }
315 error(-1, "%s: device not configured", dd->sname);
316 return(-1);
317 }
318 }
319
320 static char *
321 strbd(string1)
322 char *string1;
323 {
324 char *p, *result;
325 size_t length = 1;
326 va_list ap;
327
328 va_start(ap, string1);
329 for (p = string1; p; p = va_arg(ap, char *))
330 length += strlen(p);
331 va_end(ap);
332
333 *(result = xmalloc(length)) = '\0';
334
335 va_start(ap, string1);
336 for (p = string1; p; p = va_arg(ap, char *))
337 strcat(result, p);
338 va_end(ap);
339
340 return(result);
341 }
342