AMD64 - Fix many compile-time warnings. int/ptr type mismatches, %llx, etc.
[dragonfly.git] / sys / kern / subr_diskgpt.c
CommitLineData
39a86b92
MD
1/*
2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
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 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
c34665ce 34 * $DragonFly: src/sys/kern/subr_diskgpt.c,v 1.4 2007/07/20 17:21:51 dillon Exp $
39a86b92
MD
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/conf.h>
40#include <sys/endian.h>
41#include <sys/diskslice.h>
42#include <sys/diskmbr.h>
43#include <sys/disk.h>
44#include <sys/buf.h>
45#include <sys/malloc.h>
46#include <sys/syslog.h>
47#include <sys/bus.h>
48#include <sys/device.h>
49#include <sys/gpt.h>
50
51#define arysize(ary) (sizeof(ary)/sizeof((ary)[0]))
52
53static void gpt_setslice(const char *sname, struct disk_info *info,
54 struct diskslice *sp, struct gpt_ent *sent);
55
56/*
57 * Handle GPT on raw disk. Note that GPTs are not recursive. The MBR is
58 * ignored once a GPT has been detected.
59 *
60 * GPTs always start at block #1, regardless of how the MBR has been set up.
61 * In fact, the MBR's starting block might be pointing to the boot partition
62 * in the GPT rather then to the start of the GPT.
63 *
64 * This routine is called from mbrinit() when a GPT has been detected.
65 */
66int
67gptinit(cdev_t dev, struct disk_info *info, struct diskslices **sspp)
68{
69 struct buf *bp1 = NULL;
70 struct buf *bp2 = NULL;
71 struct gpt_hdr *gpt;
72 struct gpt_ent *ent;
73 struct diskslice *sp;
74 struct diskslices *ssp;
75 cdev_t wdev;
76 int error;
77 uint32_t len;
78 uint32_t entries;
79 uint32_t entsz;
80 uint32_t crc;
81 uint32_t table_lba;
82 uint32_t table_blocks;
83 int i = 0, j;
84 const char *dname;
85
86 /*
87 * The GPT starts in sector 1.
88 */
89 wdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), WHOLE_SLICE_PART);
90 dname = dev_dname(wdev);
91 bp1 = geteblk((int)info->d_media_blksize);
92 bp1->b_bio1.bio_offset = info->d_media_blksize;
93 bp1->b_bcount = info->d_media_blksize;
94 bp1->b_cmd = BUF_CMD_READ;
95 dev_dstrategy(wdev, &bp1->b_bio1);
96 if (biowait(bp1) != 0) {
97 kprintf("%s: reading GPT @ block 1: error %d\n",
98 dname, bp1->b_error);
99 error = EIO;
100 goto done;
101 }
102
103 /*
104 * Header sanity check
105 */
106 gpt = (void *)bp1->b_data;
107 len = le32toh(gpt->hdr_size);
108 if (len < GPT_MIN_HDR_SIZE || len > info->d_media_blksize) {
109 kprintf("%s: Illegal GPT header size %d\n", dname, len);
110 error = EINVAL;
111 goto done;
112 }
113
114 crc = le32toh(gpt->hdr_crc_self);
115 gpt->hdr_crc_self = 0;
116 if (crc32(gpt, len) != crc) {
117 kprintf("%s: GPT CRC32 did not match\n", dname);
118 error = EINVAL;
119 goto done;
120 }
121
122 /*
123 * Validate the partition table and its location, then read it
124 * into a buffer.
125 */
126 entries = le32toh(gpt->hdr_entries);
127 entsz = le32toh(gpt->hdr_entsz);
128 table_lba = le32toh(gpt->hdr_lba_table);
129 table_blocks = (entries * entsz + info->d_media_blksize - 1) /
130 info->d_media_blksize;
131 if (entries < 1 || entries > 128 ||
132 entsz < 128 || (entsz & 7) || entsz > MAXBSIZE / entries ||
133 table_lba < 2 || table_lba + table_blocks > info->d_media_blocks) {
134 kprintf("%s: GPT partition table is out of bounds\n", dname);
135 error = EINVAL;
136 goto done;
137 }
138
c34665ce
MD
139 /*
140 * XXX subject to device dma size limitations
141 */
39a86b92
MD
142 bp2 = geteblk((int)(table_blocks * info->d_media_blksize));
143 bp2->b_bio1.bio_offset = (off_t)table_lba * info->d_media_blksize;
144 bp2->b_bcount = table_blocks * info->d_media_blksize;
145 bp2->b_cmd = BUF_CMD_READ;
146 dev_dstrategy(wdev, &bp2->b_bio1);
147 if (biowait(bp2) != 0) {
148 kprintf("%s: reading GPT partition table @ %lld: error %d\n",
973c11b9
MD
149 dname,
150 (long long)bp2->b_bio1.bio_offset,
151 bp2->b_error);
39a86b92
MD
152 error = EIO;
153 goto done;
154 }
155
156 /*
157 * We are passed a pointer to a minimal slices struct. Replace
ae81fc47
MD
158 * it with a maximal one (128 slices + special slices). Well,
159 * really there is only one special slice (the WHOLE_DISK_SLICE)
160 * since we use the compatibility slice for s0, but don't quibble.
161 *
39a86b92
MD
162 */
163 kfree(*sspp, M_DEVBUF);
ae81fc47 164 ssp = *sspp = dsmakeslicestruct(BASE_SLICE+128, info);
39a86b92
MD
165
166 /*
167 * Create a slice for each partition.
168 */
ae81fc47 169 for (i = 0; i < (int)entries && i < 128; ++i) {
39a86b92
MD
170 struct gpt_ent sent;
171 char partname[2];
172 char *sname;
173
174 ent = (void *)((char *)bp2->b_data + i * entsz);
175 le_uuid_dec(&ent->ent_type, &sent.ent_type);
176 le_uuid_dec(&ent->ent_uuid, &sent.ent_uuid);
177 sent.ent_lba_start = le64toh(ent->ent_lba_start);
178 sent.ent_lba_end = le64toh(ent->ent_lba_end);
179 sent.ent_attr = le64toh(ent->ent_attr);
180
181 for (j = 0; j < arysize(ent->ent_name); ++j)
182 sent.ent_name[j] = le16toh(ent->ent_name[j]);
183
184 /*
185 * The COMPATIBILITY_SLICE is actually slice 0 (s0). This
186 * is a bit weird becaue the whole-disk slice is #1, so
187 * slice 1 (s1) starts at BASE_SLICE.
188 */
189 if (i == 0)
190 sp = &ssp->dss_slices[COMPATIBILITY_SLICE];
191 else
ae81fc47 192 sp = &ssp->dss_slices[BASE_SLICE+i-1];
39a86b92
MD
193 sname = dsname(dev, dkunit(dev), WHOLE_DISK_SLICE,
194 WHOLE_SLICE_PART, partname);
195
196 if (kuuid_is_nil(&sent.ent_type))
197 continue;
198
199 if (sent.ent_lba_start < table_lba + table_blocks ||
ae81fc47
MD
200 sent.ent_lba_end >= info->d_media_blocks ||
201 sent.ent_lba_start >= sent.ent_lba_end) {
39a86b92
MD
202 kprintf("%s part %d: unavailable, bad start or "
203 "ending lba\n",
204 sname, i);
205 } else {
206 gpt_setslice(sname, info, sp, &sent);
207 }
208 }
209 ssp->dss_nslices = BASE_SLICE + i;
210
211 error = 0;
212done:
213 if (bp1) {
214 bp1->b_flags |= B_INVAL | B_AGE;
215 brelse(bp1);
216 }
217 if (bp2) {
218 bp2->b_flags |= B_INVAL | B_AGE;
219 brelse(bp2);
220 }
221 if (error == EINVAL)
222 error = 0;
223 return (error);
224}
225
226static
227void
228gpt_setslice(const char *sname, struct disk_info *info, struct diskslice *sp,
229 struct gpt_ent *sent)
230{
231 sp->ds_offset = sent->ent_lba_start;
232 sp->ds_size = sent->ent_lba_end + 1 - sent->ent_lba_start;
233 sp->ds_type = 1; /* XXX */
18cb7add
MD
234 sp->ds_type_uuid = sent->ent_type;
235 sp->ds_stor_uuid = sent->ent_uuid;
39a86b92
MD
236 sp->ds_reserved = 0; /* no reserved sectors */
237}
238