Collapse gd_astpending and gd_reqpri together into gd_reqflags. gd_reqflags
[dragonfly.git] / lib / libdisk / write_disk.c
1 /*
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
5  * can do whatever you want with this stuff. If we meet some day, and you think
6  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7  * ----------------------------------------------------------------------------
8  *
9  * $FreeBSD: src/lib/libdisk/write_disk.c,v 1.28.2.10 2001/05/13 21:01:38 jkh Exp $
10  * $DragonFly: src/lib/libdisk/Attic/write_disk.c,v 1.2 2003/06/17 04:26:49 dillon Exp $
11  *
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/ioctl.h>
22 #include <sys/disklabel.h>
23 #include <sys/diskslice.h>
24 #include <paths.h>
25 #include "libdisk.h"
26
27 #define DOSPTYP_EXTENDED        5
28 #define BBSIZE                  8192
29 #define SBSIZE                  8192
30 #define DEF_RPM                 3600
31 #define DEF_INTERLEAVE  1
32
33 #ifdef PC98
34 #define WHERE(offset,disk) (offset)
35 #else
36 #define WHERE(offset,disk) (disk->flags & DISK_ON_TRACK ? offset + 63 : offset)
37 #endif
38
39 /* XXX: A lot of hardcoded 512s probably should be foo->sector_size;
40         I'm not sure which, so I leave it like it worked before. --schweikh */
41 int
42 Write_FreeBSD(int fd, struct disk *new, struct disk *old, struct chunk *c1)
43 {
44         struct disklabel *dl;
45         struct chunk *c2;
46         int i,j;
47         void *p;
48         u_char buf[BBSIZE];
49 #ifdef __alpha__
50         u_long *lp, sum;
51 #endif
52
53         for(i = 0; i < BBSIZE/512; i++) {
54                 p = read_block(fd, WHERE(i + c1->offset, new), 512);
55                 memcpy(buf + 512 * i, p, 512);
56                 free(p);
57         }
58 #if defined(__i386__)
59         if(new->boot1)
60                 memcpy(buf, new->boot1, 512);
61
62         if(new->boot2)
63                 memcpy(buf + 512, new->boot2, BBSIZE-512);
64 #elif defined(__alpha__)
65         if(new->boot1)
66                 memcpy(buf + 512, new->boot1, BBSIZE-512);
67 #endif
68
69         dl = (struct disklabel *)(buf + 512 * LABELSECTOR + LABELOFFSET);
70         memset(dl, 0, sizeof *dl);
71
72         for(c2 = c1->part; c2; c2 = c2->next) {
73                 if (c2->type == unused) continue;
74                 if (!strcmp(c2->name, "X")) continue;
75 #ifdef __alpha__
76                 j = c2->name[strlen(c2->name) - 1] - 'a';
77 #else
78                 j = c2->name[strlen(new->name) + 2] - 'a';
79 #endif
80                 if (j < 0 || j >= MAXPARTITIONS || j == RAW_PART) {
81 #ifdef DEBUG
82                         warn("weird partition letter %c", c2->name[strlen(new->name) + 2]);
83 #endif
84                         continue;
85                 }
86                 dl->d_partitions[j].p_size = c2->size;
87                 dl->d_partitions[j].p_offset = c2->offset;
88                 dl->d_partitions[j].p_fstype = c2->subtype;
89         }
90
91         dl->d_bbsize = BBSIZE;
92         /*
93          * Add in defaults for superblock size, interleave, and rpms
94          */
95         dl->d_sbsize = SBSIZE;
96         dl->d_interleave = DEF_INTERLEAVE;
97         dl->d_rpm = DEF_RPM;
98
99         strcpy(dl->d_typename, c1->name);
100
101         dl->d_secsize = 512;
102         dl->d_secperunit = new->chunks->size;
103         dl->d_ncylinders =  new->bios_cyl;
104         dl->d_ntracks =  new->bios_hd;
105         dl->d_nsectors =  new->bios_sect;
106         dl->d_secpercyl = dl->d_ntracks * dl->d_nsectors;
107
108         dl->d_npartitions = MAXPARTITIONS;
109
110         dl->d_type = new->name[0] == 's' || new->name[0] == 'd' ||
111             new->name[0] == 'o' ? DTYPE_SCSI : DTYPE_ESDI;
112         dl->d_partitions[RAW_PART].p_size = c1->size;
113         dl->d_partitions[RAW_PART].p_offset = c1->offset;
114 #ifdef PC98
115         dl->d_rpm = 3600;
116         dl->d_interleave = 1;
117 #endif
118
119 #ifndef PC98
120         if(new->flags & DISK_ON_TRACK)
121                 for(i=0;i<MAXPARTITIONS;i++)
122                         if (dl->d_partitions[i].p_size)
123                                 dl->d_partitions[i].p_offset += 63;
124 #endif
125         dl->d_magic = DISKMAGIC;
126         dl->d_magic2 = DISKMAGIC;
127         dl->d_checksum = dkcksum(dl);
128
129 #ifdef __alpha__
130         /*
131          * Tell SRM where the bootstrap is.
132          */
133         lp = (u_long *)buf;
134         lp[60] = 15;
135         lp[61] = 1;
136         lp[62] = 0;
137
138         /*
139          * Generate the bootblock checksum for the SRM console.
140          */
141         for (lp = (u_long *)buf, i = 0, sum = 0; i < 63; i++)
142             sum += lp[i];
143         lp[63] = sum;
144 #endif /*__alpha__*/
145
146         for(i=0;i<BBSIZE/512;i++) {
147                 write_block(fd,WHERE(i + c1->offset, new), buf + 512 * i, 512);
148         }
149
150         return 0;
151 }
152
153 int
154 Write_Extended(int fd, struct disk *new, struct disk *old, struct chunk *c1)
155 {
156         return 0;
157 }
158
159 #if defined(__i386__) && !defined(PC98)
160 static void
161 Write_Int32(u_int32_t *p, u_int32_t v)
162 {
163     u_int8_t *bp = (u_int8_t *)p;
164     bp[0] = (v >> 0) & 0xff;
165     bp[1] = (v >> 8) & 0xff;
166     bp[2] = (v >> 16) & 0xff;
167     bp[3] = (v >> 24) & 0xff;
168 }
169 #endif
170
171 #if defined(__i386__) && !defined(PC98)
172 /*
173  * Special install-time configuration for the i386 boot0 boot manager.
174  */
175 static void
176 Cfg_Boot_Mgr(u_char *mbr, int edd)
177 {
178     if (mbr[0x1b0] == 0x66 && mbr[0x1b1] == 0xbb) {
179         if (edd)
180             mbr[0x1bb] |= 0x80; /* Packet mode on */
181         else
182             mbr[0x1bb] &= 0x7f; /* Packet mode off */
183     }
184 }
185 #endif
186
187 int
188 Write_Disk(struct disk *d1)
189 {
190         int fd,i;
191 #ifdef __i386__
192         int j;
193 #endif
194         struct disk *old = 0;
195         struct chunk *c1;
196         int ret = 0;
197         char device[64];
198         u_char *mbr;
199         struct dos_partition *dp,work[NDOSPART];
200 #ifdef PC98
201         int s[7];
202         int PC98_EntireDisk = 0;
203 #else
204         int s[4];
205 #ifdef __i386__
206         int need_edd = 0;       /* Need EDD (packet interface) */
207 #endif
208 #endif
209         int one = 1;
210         int zero = 0;
211
212         strcpy(device,_PATH_DEV);
213         strcat(device,d1->name);
214
215 #ifdef PC98
216         /* XXX - for entire FreeBSD(98) */
217         for (c1 = d1->chunks->part; c1; c1 = c1->next) {
218             if ((c1->type == freebsd) || (c1->offset == 0))
219                 device[9] = 0;
220         }
221 #endif
222
223         fd = open(device,O_RDWR);
224         if (fd < 0) {
225 #ifdef DEBUG
226                 warn("open(%s) failed", device);
227 #endif
228                 return 1;
229         }
230         ioctl(fd, DIOCWLABEL, &one);
231
232         memset(s,0,sizeof s);
233 #ifdef PC98
234         mbr = read_block(fd, WHERE(1, d1), d1->sector_size);
235 #else
236         mbr = read_block(fd, WHERE(0, d1), d1->sector_size);
237 #endif
238         dp = (struct dos_partition*)(mbr + DOSPARTOFF);
239         memcpy(work, dp, sizeof work);
240         dp = work;
241         free(mbr);
242         for (c1 = d1->chunks->part; c1; c1 = c1->next) {
243                 if (c1->type == unused) continue;
244                 if (!strcmp(c1->name, "X")) continue;
245 #ifdef __i386__
246                 j = c1->name[4] - '1';
247                 j = c1->name[strlen(d1->name) + 1] - '1';
248 #ifdef PC98
249                 if (j < 0 || j > 7)
250 #else
251                 if (j < 0 || j > 3)
252 #endif
253                         continue;
254                 s[j]++;
255 #endif
256 #ifndef PC98
257                 if (c1->type == extended)
258                         ret += Write_Extended(fd, d1, old, c1);
259 #endif
260                 if (c1->type == freebsd)
261                         ret += Write_FreeBSD(fd, d1, old, c1);
262
263 #ifdef __i386__
264 #ifndef PC98
265                 Write_Int32(&dp[j].dp_start, c1->offset);
266                 Write_Int32(&dp[j].dp_size, c1->size);
267 #endif
268
269                 i = c1->offset;
270 #ifdef PC98
271                 dp[j].dp_ssect = dp[j].dp_ipl_sct = i % d1->bios_sect;
272                 i -= dp[j].dp_ssect;
273                 i /= d1->bios_sect;
274                 dp[j].dp_shd = dp[j].dp_ipl_head = i % d1->bios_hd;
275                 i -= dp[j].dp_shd;
276                 i /= d1->bios_hd;
277                 dp[j].dp_scyl = dp[j].dp_ipl_cyl = i;
278 #else
279                 if (i >= 1024*d1->bios_sect*d1->bios_hd) {
280                         dp[j].dp_ssect = 0xff;
281                         dp[j].dp_shd = 0xff;
282                         dp[j].dp_scyl = 0xff;
283                         need_edd++;
284                 } else {
285                         dp[j].dp_ssect = i % d1->bios_sect;
286                         i -= dp[j].dp_ssect++;
287                         i /= d1->bios_sect;
288                         dp[j].dp_shd =  i % d1->bios_hd;
289                         i -= dp[j].dp_shd;
290                         i /= d1->bios_hd;
291                         dp[j].dp_scyl = i;
292                         i -= dp[j].dp_scyl;
293                         dp[j].dp_ssect |= i >> 2;
294                 }
295 #endif /* PC98 */
296
297 #ifdef DEBUG
298                 printf("S:%lu = (%x/%x/%x)",
299                         c1->offset, dp[j].dp_scyl, dp[j].dp_shd, dp[j].dp_ssect);
300 #endif
301
302                 i = c1->end;
303 #ifdef PC98
304 #if 1
305                 dp[j].dp_esect = dp[j].dp_ehd = 0;
306                 dp[j].dp_ecyl = i / (d1->bios_sect * d1->bios_hd);
307 #else
308                 dp[j].dp_esect = i % d1->bios_sect;
309                 i -= dp[j].dp_esect;
310                 i /= d1->bios_sect;
311                 dp[j].dp_ehd =  i % d1->bios_hd;
312                 i -= dp[j].dp_ehd;
313                 i /= d1->bios_hd;
314                 dp[j].dp_ecyl = i;
315 #endif
316 #else
317                 dp[j].dp_esect = i % d1->bios_sect;
318                 i -= dp[j].dp_esect++;
319                 i /= d1->bios_sect;
320                 dp[j].dp_ehd =  i % d1->bios_hd;
321                 i -= dp[j].dp_ehd;
322                 i /= d1->bios_hd;
323                 if (i>1023) i = 1023;
324                 dp[j].dp_ecyl = i;
325                 i -= dp[j].dp_ecyl;
326                 dp[j].dp_esect |= i >> 2;
327 #endif
328
329 #ifdef DEBUG
330                 printf("  E:%lu = (%x/%x/%x)\n",
331                         c1->end, dp[j].dp_ecyl, dp[j].dp_ehd, dp[j].dp_esect);
332 #endif
333
334 #ifdef PC98
335                 dp[j].dp_mid = c1->subtype & 0xff;
336                 dp[j].dp_sid = c1->subtype >> 8;
337                 if (c1->flags & CHUNK_ACTIVE)
338                         dp[j].dp_mid |= 0x80;
339
340                 strncpy(dp[j].dp_name, c1->sname, 16);
341 #else
342                 dp[j].dp_typ = c1->subtype;
343                 if (c1->flags & CHUNK_ACTIVE)
344                         dp[j].dp_flag = 0x80;
345                 else
346                         dp[j].dp_flag = 0;
347 #endif
348 #endif
349         }
350 #ifdef __i386__
351         j = 0;
352         for(i = 0; i < NDOSPART; i++) {
353                 if (!s[i])
354                         memset(dp + i, 0, sizeof *dp);
355 #ifndef PC98
356                 if (dp[i].dp_flag)
357                         j++;
358 #endif
359         }
360 #ifndef PC98
361         if (!j)
362                 for(i = 0; i < NDOSPART; i++)
363                         if (dp[i].dp_typ == 0xa5)
364                                 dp[i].dp_flag = 0x80;
365 #endif
366
367 #ifdef PC98
368         if (d1->bootipl)
369                 write_block(fd, WHERE(0, d1), d1->bootipl, d1->sector_size);
370
371         mbr = read_block(fd, WHERE(1, d1), d1->sector_size);
372         memcpy(mbr + DOSPARTOFF, dp, sizeof *dp * NDOSPART);
373         /* XXX - for entire FreeBSD(98) */
374         for (c1 = d1->chunks->part; c1; c1 = c1->next)
375                 if (((c1->type == freebsd) || (c1->type == fat))
376                          && (c1->offset == 0))
377                         PC98_EntireDisk = 1;
378         if (PC98_EntireDisk == 0)
379                 write_block(fd, WHERE(1, d1), mbr, d1->sector_size);
380
381         if (d1->bootmenu)
382                 for (i = 0; i * d1->sector_size < d1->bootmenu_size; i++)
383                         write_block(fd, WHERE(2 + i, d1), &d1->bootmenu[i * d1->sector_size], d1->sector_size);
384 #else
385         mbr = read_block(fd, WHERE(0, d1), d1->sector_size);
386         if (d1->bootmgr) {
387                 memcpy(mbr, d1->bootmgr, DOSPARTOFF);
388                 Cfg_Boot_Mgr(mbr, need_edd);
389         }
390         memcpy(mbr + DOSPARTOFF, dp, sizeof *dp * NDOSPART);
391         mbr[512-2] = 0x55;
392         mbr[512-1] = 0xaa;
393         write_block(fd, WHERE(0, d1), mbr, d1->sector_size);
394         if (d1->bootmgr && d1->bootmgr_size > d1->sector_size)
395           for(i = 1; i * d1->sector_size <= d1->bootmgr_size; i++)
396             write_block(fd, WHERE(i, d1), &d1->bootmgr[i * d1->sector_size], d1->sector_size);
397 #endif
398 #endif
399
400         i = 1;
401         i = ioctl(fd, DIOCSYNCSLICEINFO, &i);
402 #ifdef DEBUG
403         if (i != 0)
404                 warn("ioctl(DIOCSYNCSLICEINFO)");
405 #endif
406         ioctl(fd, DIOCWLABEL, &zero);
407         close(fd);
408         return 0;
409 }