]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/geom/part/g_part_pc98.c
add -n option to suppress clearing the build tree and add -DNO_CLEAN
[FreeBSD/FreeBSD.git] / sys / geom / part / g_part_pc98.c
1 /*-
2  * Copyright (c) 2008 Marcel Moolenaar
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  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/bio.h>
32 #include <sys/diskpc98.h>
33 #include <sys/endian.h>
34 #include <sys/kernel.h>
35 #include <sys/kobj.h>
36 #include <sys/limits.h>
37 #include <sys/lock.h>
38 #include <sys/malloc.h>
39 #include <sys/mutex.h>
40 #include <sys/queue.h>
41 #include <sys/sbuf.h>
42 #include <sys/systm.h>
43 #include <geom/geom.h>
44 #include <geom/part/g_part.h>
45
46 #include "g_part_if.h"
47
48 #define SECSIZE         512
49
50 struct g_part_pc98_table {
51         struct g_part_table     base;
52         u_char          boot[SECSIZE];
53         u_char          table[SECSIZE];
54 };
55
56 struct g_part_pc98_entry {
57         struct g_part_entry     base;
58         struct pc98_partition ent;
59 };
60
61 static int g_part_pc98_add(struct g_part_table *, struct g_part_entry *,
62     struct g_part_parms *);
63 static int g_part_pc98_bootcode(struct g_part_table *, struct g_part_parms *);
64 static int g_part_pc98_create(struct g_part_table *, struct g_part_parms *);
65 static int g_part_pc98_destroy(struct g_part_table *, struct g_part_parms *);
66 static int g_part_pc98_dumpconf(struct g_part_table *, struct g_part_entry *,
67     struct sbuf *, const char *);
68 static int g_part_pc98_dumpto(struct g_part_table *, struct g_part_entry *);
69 static int g_part_pc98_modify(struct g_part_table *, struct g_part_entry *,  
70     struct g_part_parms *);
71 static char *g_part_pc98_name(struct g_part_table *, struct g_part_entry *,
72     char *, size_t);
73 static int g_part_pc98_probe(struct g_part_table *, struct g_consumer *);
74 static int g_part_pc98_read(struct g_part_table *, struct g_consumer *);
75 static const char *g_part_pc98_type(struct g_part_table *, struct g_part_entry *,
76     char *, size_t);
77 static int g_part_pc98_write(struct g_part_table *, struct g_consumer *);
78
79 static kobj_method_t g_part_pc98_methods[] = {
80         KOBJMETHOD(g_part_add,          g_part_pc98_add),
81         KOBJMETHOD(g_part_bootcode,     g_part_pc98_bootcode),
82         KOBJMETHOD(g_part_create,       g_part_pc98_create),
83         KOBJMETHOD(g_part_destroy,      g_part_pc98_destroy),
84         KOBJMETHOD(g_part_dumpconf,     g_part_pc98_dumpconf),
85         KOBJMETHOD(g_part_dumpto,       g_part_pc98_dumpto),
86         KOBJMETHOD(g_part_modify,       g_part_pc98_modify),
87         KOBJMETHOD(g_part_name,         g_part_pc98_name),
88         KOBJMETHOD(g_part_probe,        g_part_pc98_probe),
89         KOBJMETHOD(g_part_read,         g_part_pc98_read),
90         KOBJMETHOD(g_part_type,         g_part_pc98_type),
91         KOBJMETHOD(g_part_write,        g_part_pc98_write),
92         { 0, 0 }
93 };
94
95 static struct g_part_scheme g_part_pc98_scheme = {
96         "PC98",
97         g_part_pc98_methods,
98         sizeof(struct g_part_pc98_table),
99         .gps_entrysz = sizeof(struct g_part_pc98_entry),
100         .gps_minent = NDOSPART,
101         .gps_maxent = NDOSPART,
102         .gps_bootcodesz = SECSIZE,
103 };
104 G_PART_SCHEME_DECLARE(g_part_pc98);
105
106 static int
107 pc98_parse_type(const char *type, u_char *dp_mid, u_char *dp_sid)
108 {
109         const char *alias;
110         char *endp;
111         long lt;
112
113         if (type[0] == '!') {
114                 lt = strtol(type + 1, &endp, 0);
115                 if (type[1] == '\0' || *endp != '\0' || lt <= 0 ||
116                     lt >= 65536)
117                         return (EINVAL);
118                 *dp_mid = (u_char)lt;
119                 *dp_sid = (u_char)(lt >> 8);
120                 return (0);
121         }
122         alias = g_part_alias_name(G_PART_ALIAS_FREEBSD);
123         if (!strcasecmp(type, alias)) {
124                 *dp_mid = (u_char)DOSMID_386BSD;
125                 *dp_sid = (u_char)DOSSID_386BSD;
126                 return (0);
127         }
128         return (EINVAL);
129 }
130
131 static void
132 pc98_set_chs(struct g_part_table *table, uint32_t lba, u_short *cylp,
133     u_char *hdp, u_char *secp)
134 {
135         uint32_t cyl, hd, sec;
136
137         sec = lba % table->gpt_sectors + 1;
138         lba /= table->gpt_sectors;
139         hd = lba % table->gpt_heads;
140         lba /= table->gpt_heads;
141         cyl = lba;
142
143         *cylp = htole16(cyl);
144         *hdp = hd;
145         *secp = sec;
146 }
147
148 static int
149 g_part_pc98_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
150     struct g_part_parms *gpp)
151 {
152         struct g_part_pc98_entry *entry;
153         struct g_part_pc98_table *table;
154         uint32_t cyl, start, size;
155
156         if (gpp->gpp_parms & G_PART_PARM_LABEL)
157                 return (EINVAL);
158
159         cyl = basetable->gpt_heads * basetable->gpt_sectors;
160
161         entry = (struct g_part_pc98_entry *)baseentry;
162         table = (struct g_part_pc98_table *)basetable;
163
164         start = gpp->gpp_start;
165         size = gpp->gpp_size;
166         if (size < cyl)
167                 return (EINVAL);
168         if (start % cyl) {
169                 size = size - cyl + (start % cyl);
170                 start = start - (start % cyl) + cyl;
171         }
172         if (size % cyl)
173                 size = size - (size % cyl);
174         if (size < cyl)
175                 return (EINVAL);
176
177         if (baseentry->gpe_deleted)
178                 bzero(&entry->ent, sizeof(entry->ent));
179
180         KASSERT(baseentry->gpe_start <= start, (__func__));
181         KASSERT(baseentry->gpe_end >= start + size - 1, (__func__));
182         baseentry->gpe_start = start;
183         baseentry->gpe_end = start + size - 1;
184         pc98_set_chs(basetable, baseentry->gpe_start, &entry->ent.dp_scyl,
185             &entry->ent.dp_shd, &entry->ent.dp_ssect);
186         pc98_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl,
187             &entry->ent.dp_ehd, &entry->ent.dp_esect);
188         return (pc98_parse_type(gpp->gpp_type, &entry->ent.dp_mid,
189             &entry->ent.dp_sid));
190 }
191
192 static int
193 g_part_pc98_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp)
194 {
195         struct g_part_pc98_table *table;
196
197         table = (struct g_part_pc98_table *)basetable;
198         bcopy(gpp->gpp_codeptr, table->boot, DOSMAGICOFFSET);
199         return (0);
200 }
201
202 static int
203 g_part_pc98_create(struct g_part_table *basetable, struct g_part_parms *gpp)
204 {
205         struct g_consumer *cp;
206         struct g_provider *pp;
207         struct g_part_pc98_table *table;
208         uint64_t msize;
209         uint32_t cyl;
210
211         pp = gpp->gpp_provider;
212         cp = LIST_FIRST(&pp->consumers);
213
214         if (pp->sectorsize < SECSIZE || pp->mediasize < 2 * SECSIZE)
215                 return (ENOSPC);
216         if (pp->sectorsize > SECSIZE)
217                 return (ENXIO);
218
219         cyl = basetable->gpt_heads * basetable->gpt_sectors;
220
221         msize = pp->mediasize / SECSIZE;
222         basetable->gpt_first = cyl;
223         basetable->gpt_last = msize - (msize % cyl) - 1;
224
225         table = (struct g_part_pc98_table *)basetable;
226         le16enc(table->boot + DOSMAGICOFFSET, DOSMAGIC);
227         return (0);
228 }
229
230 static int
231 g_part_pc98_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
232 {
233
234         /* Wipe the first two sectors to clear the partitioning. */
235         basetable->gpt_smhead |= 3;
236         return (0);
237 }
238
239 static int
240 g_part_pc98_dumpconf(struct g_part_table *table,
241     struct g_part_entry *baseentry, struct sbuf *sb, const char *indent)
242 {
243         struct g_part_pc98_entry *entry;
244         char name[sizeof(entry->ent.dp_name) + 1];
245         u_int type;
246
247         entry = (struct g_part_pc98_entry *)baseentry;
248         if (entry == NULL) {
249                 /* confxml: scheme information */
250                 return (0);
251         }
252
253         type = entry->ent.dp_mid + (entry->ent.dp_sid << 8);
254         strncpy(name, entry->ent.dp_name, sizeof(name) - 1);
255         name[sizeof(name) - 1] = '\0';
256         if (indent == NULL) {
257                 /* conftxt: libdisk compatibility */
258                 sbuf_printf(sb, " xs PC98 xt %u sn %s", type, name);
259         } else {
260                 /* confxml: partition entry information */
261                 sbuf_printf(sb, "%s<label>%s</label>\n", indent, name);
262                 sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent, type);
263         }
264         return (0);
265 }
266
267 static int
268 g_part_pc98_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)  
269 {
270         struct g_part_pc98_entry *entry;
271
272         /* Allow dumping to a FreeBSD partition only. */
273         entry = (struct g_part_pc98_entry *)baseentry;
274         return ((entry->ent.dp_mid == DOSMID_386BSD &&
275             entry->ent.dp_sid == DOSSID_386BSD) ? 1 : 0);
276 }
277
278 static int
279 g_part_pc98_modify(struct g_part_table *basetable,
280     struct g_part_entry *baseentry, struct g_part_parms *gpp)
281 {
282         struct g_part_pc98_entry *entry;
283
284         if (gpp->gpp_parms & G_PART_PARM_LABEL)
285                 return (EINVAL);
286
287         entry = (struct g_part_pc98_entry *)baseentry;
288         if (gpp->gpp_parms & G_PART_PARM_TYPE)
289                 return (pc98_parse_type(gpp->gpp_type, &entry->ent.dp_mid,
290                     &entry->ent.dp_sid));
291         return (0);
292 }
293
294 static char *
295 g_part_pc98_name(struct g_part_table *table, struct g_part_entry *baseentry,
296     char *buf, size_t bufsz)
297 {
298
299         snprintf(buf, bufsz, "s%d", baseentry->gpe_index);
300         return (buf);
301 }
302
303 static int
304 g_part_pc98_probe(struct g_part_table *table, struct g_consumer *cp)
305 {
306         struct g_provider *pp;
307         u_char *buf, *p;
308         int error, index, res, sum;
309         uint16_t magic;
310
311         pp = cp->provider;
312
313         /* Sanity-check the provider. */
314         if (pp->sectorsize < SECSIZE || pp->mediasize < 2 * SECSIZE)
315                 return (ENOSPC);
316         if (pp->sectorsize > SECSIZE)
317                 return (ENXIO);
318
319         /* Check that there's a PC98 partition table. */
320         buf = g_read_data(cp, 0L, 2 * SECSIZE, &error);
321         if (buf == NULL)
322                 return (error);
323
324         /* We goto out on mismatch. */
325         res = ENXIO;
326
327         magic = le16dec(buf + DOSMAGICOFFSET);
328         if (magic != DOSMAGIC)
329                 goto out;
330
331         sum = 0;
332         for (index = SECSIZE; index < 2 * SECSIZE; index++)
333                 sum += buf[index];
334         if (sum == 0) {
335                 res = G_PART_PROBE_PRI_LOW;
336                 goto out;
337         }
338
339         for (index = 0; index < NDOSPART; index++) {
340                 p = buf + SECSIZE + index * DOSPARTSIZE;
341                 if (p[2] != 0 || p[3] != 0)
342                         goto out;
343                 if (p[1] == 0)
344                         continue;
345                 if (le16dec(p + 10) == 0)
346                         goto out;
347         }
348
349         res = G_PART_PROBE_PRI_HIGH;
350
351  out:
352         g_free(buf);
353         return (res);
354 }
355
356 static int
357 g_part_pc98_read(struct g_part_table *basetable, struct g_consumer *cp)
358 {
359         struct pc98_partition ent;
360         struct g_provider *pp;
361         struct g_part_pc98_table *table;
362         struct g_part_pc98_entry *entry;
363         u_char *buf, *p;
364         off_t msize;
365         off_t start, end;
366         u_int cyl;
367         int error, index;
368
369         pp = cp->provider;
370         table = (struct g_part_pc98_table *)basetable;
371         msize = pp->mediasize / SECSIZE;
372
373         buf = g_read_data(cp, 0L, 2 * SECSIZE, &error);
374         if (buf == NULL)
375                 return (error);
376
377         cyl = basetable->gpt_heads * basetable->gpt_sectors;
378
379         bcopy(buf, table->boot, sizeof(table->boot));
380         bcopy(buf + SECSIZE, table->table, sizeof(table->table));
381
382         for (index = NDOSPART - 1; index >= 0; index--) {
383                 p = buf + SECSIZE + index * DOSPARTSIZE;
384                 ent.dp_mid = p[0];
385                 ent.dp_sid = p[1];
386                 ent.dp_dum1 = p[2];
387                 ent.dp_dum2 = p[3];
388                 ent.dp_ipl_sct = p[4];
389                 ent.dp_ipl_head = p[5];
390                 ent.dp_ipl_cyl = le16dec(p + 6);
391                 ent.dp_ssect = p[8];
392                 ent.dp_shd = p[9];
393                 ent.dp_scyl = le16dec(p + 10);
394                 ent.dp_esect = p[12];
395                 ent.dp_ehd = p[13];
396                 ent.dp_ecyl = le16dec(p + 14);
397                 bcopy(p + 16, ent.dp_name, sizeof(ent.dp_name));
398                 if (ent.dp_sid == 0)
399                         continue;
400
401                 start = ent.dp_scyl * cyl;
402                 end = (ent.dp_ecyl + 1) * cyl - 1;
403                 entry = (struct g_part_pc98_entry *)g_part_new_entry(basetable,
404                     index + 1, start, end);
405                 entry->ent = ent;
406         }
407
408         basetable->gpt_entries = NDOSPART;
409         basetable->gpt_first = cyl;
410         basetable->gpt_last = msize - (msize % cyl) - 1;
411
412         return (0);
413 }
414
415 static const char *
416 g_part_pc98_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 
417     char *buf, size_t bufsz)
418 {
419         struct g_part_pc98_entry *entry;
420         u_int type;
421
422         entry = (struct g_part_pc98_entry *)baseentry;
423         type = entry->ent.dp_mid + (entry->ent.dp_sid << 8);
424         if (type == DOSPTYP_386BSD)
425                 return (g_part_alias_name(G_PART_ALIAS_FREEBSD));
426         snprintf(buf, bufsz, "!%d", type);
427         return (buf);
428 }
429
430 static int
431 g_part_pc98_write(struct g_part_table *basetable, struct g_consumer *cp)
432 {
433         struct g_part_entry *baseentry;
434         struct g_part_pc98_entry *entry;
435         struct g_part_pc98_table *table;
436         u_char *p;
437         int error, index;
438
439         table = (struct g_part_pc98_table *)basetable;
440         baseentry = LIST_FIRST(&basetable->gpt_entry);
441         for (index = 1; index <= basetable->gpt_entries; index++) {
442                 p = table->table + (index - 1) * DOSPARTSIZE;
443                 entry = (baseentry != NULL && index == baseentry->gpe_index)
444                     ? (struct g_part_pc98_entry *)baseentry : NULL;
445                 if (entry != NULL && !baseentry->gpe_deleted) {
446                         p[0] = entry->ent.dp_mid;
447                         p[1] = entry->ent.dp_sid;
448                         p[2] = entry->ent.dp_dum1;
449                         p[3] = entry->ent.dp_dum2;
450                         p[4] = entry->ent.dp_ipl_sct;
451                         p[5] = entry->ent.dp_ipl_head;
452                         le16enc(p + 6, entry->ent.dp_ipl_cyl);
453                         p[8] = entry->ent.dp_ssect;
454                         p[9] = entry->ent.dp_shd;
455                         le16enc(p + 10, entry->ent.dp_scyl);
456                         p[12] = entry->ent.dp_esect;
457                         p[13] = entry->ent.dp_ehd;
458                         le16enc(p + 14, entry->ent.dp_ecyl);
459                         bcopy(entry->ent.dp_name, p + 16,
460                             sizeof(entry->ent.dp_name));
461                 } else
462                         bzero(p, DOSPARTSIZE);
463
464                 if (entry != NULL)
465                         baseentry = LIST_NEXT(baseentry, gpe_entry);
466         }
467
468         error = g_write_data(cp, 0, table->boot, SECSIZE);
469         if (!error)
470                 error = g_write_data(cp, SECSIZE, table->table, SECSIZE);
471         return (error);
472 }