Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | pj | 1 | /* |
2 | * Project: S.Ha.R.K. |
||
3 | * |
||
4 | * Coordinators: |
||
5 | * Giorgio Buttazzo <giorgio@sssup.it> |
||
6 | * Paolo Gai <pj@gandalf.sssup.it> |
||
7 | * |
||
8 | * Authors : |
||
9 | * Paolo Gai <pj@gandalf.sssup.it> |
||
10 | * Massimiliano Giorgi <massy@gandalf.sssup.it> |
||
11 | * Luca Abeni <luca@gandalf.sssup.it> |
||
12 | * (see the web pages for full authors list) |
||
13 | * |
||
14 | * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy) |
||
15 | * |
||
16 | * http://www.sssup.it |
||
17 | * http://retis.sssup.it |
||
18 | * http://shark.sssup.it |
||
19 | */ |
||
20 | |||
21 | |||
22 | /*************************************** |
||
23 | |||
24 | CVS : $Id: lodsk.c,v 1.1.1.1 2002-03-29 14:12:49 pj Exp $ |
||
25 | |||
26 | Revision: $Revision: 1.1.1.1 $ |
||
27 | |||
28 | Last update: $Date: 2002-03-29 14:12:49 $ |
||
29 | |||
30 | This module is used by block device sub-system to scan a physical |
||
31 | hard disk to find logical layout (partition scheme). |
||
32 | |||
33 | ***************************************/ |
||
34 | |||
35 | /* |
||
36 | * Copyright (C) 1999 Massimiliano Giorgi |
||
37 | * |
||
38 | * This program is free software; you can redistribute it and/or modify |
||
39 | * it under the terms of the GNU General Public License as published by |
||
40 | * the Free Software Foundation; either version 2 of the License, or |
||
41 | * (at your option) any later version. |
||
42 | * |
||
43 | * This program is distributed in the hope that it will be useful, |
||
44 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
45 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
46 | * GNU General Public License for more details. |
||
47 | * |
||
48 | * You should have received a copy of the GNU General Public License |
||
49 | * along with this program; if not, write to the Free Software |
||
50 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
51 | * |
||
52 | */ |
||
53 | |||
54 | #include "glue.h" |
||
55 | |||
56 | #include "bdev.h" |
||
57 | #include "sysind.h" |
||
58 | #include "lodsk.h" |
||
59 | |||
60 | /*+ Log Level used to report an error +*/ |
||
61 | #define LODSKERRLOG KERN_ERR |
||
62 | |||
63 | /*+ Log level used to inform +*/ |
||
64 | #define LODSKLOG KERN_NOTICE |
||
65 | |||
66 | /*+ An aligned buffer for data I/O +*/ |
||
67 | static __uint8_t buffer[512] __attribute__ ((aligned(4))); |
||
68 | |||
69 | /*++++++++++++++++++++++++++++++++++++++ |
||
70 | |||
71 | This function convert a physical partion structure to a partition |
||
72 | structure (the difference is that the physical partition structure |
||
73 | has a "strange" layout and must be parsed to find actually values that |
||
74 | are saved into a partition structure). |
||
75 | |||
76 | struct phpartition *ph |
||
77 | physical partition to parse |
||
78 | |||
79 | struct partition *lo |
||
80 | values are stored into this structure |
||
81 | ++++++++++++++++++++++++++++++++++++++*/ |
||
82 | |||
83 | static void partph2lo(struct phpartition *ph,struct partition *lo) |
||
84 | { |
||
85 | lo->boot_ind=((ph->boot_ind&0x80)?1:0); |
||
86 | lo->sys_ind=ph->sys_ind; |
||
87 | lo->rel_sect=ph->rel_sect; |
||
88 | lo->nr_sects=ph->nr_sects; |
||
89 | /**/ |
||
90 | lo->st_head=ph->st_h; |
||
91 | lo->st_sect=ph->st_s&0x3f; |
||
92 | lo->st_cyl=(__uint16_t)ph->st_c|(((__uint16_t)ph->st_s&0xc0)<<2); |
||
93 | lo->en_head=ph->st_h; |
||
94 | lo->en_sect=ph->en_s&0x3f; |
||
95 | lo->en_cyl=(__uint16_t)ph->en_c|(((__uint16_t)ph->en_s&0xc0)<<2); |
||
96 | } |
||
97 | |||
98 | /*++++++++++++++++++++++++++++++++++++++ |
||
99 | |||
100 | Find if a partition is an extended partition. |
||
101 | |||
102 | #define is_extended_partition |
||
103 | return 0 if no, other value if yes |
||
104 | |||
105 | sys_ind |
||
106 | "system indicator" for that partition |
||
107 | ++++++++++++++++++++++++++++++++++++++*/ |
||
108 | |||
109 | #define is_extended_partition(sys_ind) ( \ |
||
110 | (sys_ind) == DOS_EXTENDED_PARTITION || \ |
||
111 | (sys_ind) == WIN98_EXTENDED_PARTITION || \ |
||
112 | (sys_ind) == LINUX_EXTENDED_PARTITION \ |
||
113 | ) |
||
114 | |||
115 | /*++++++++++++++++++++++++++++++++++++++ |
||
116 | |||
117 | Scan recursiverly an extended partition to find other partition (this |
||
118 | function suppose an IBM PC hard disk architecture). |
||
119 | When a new partition is found the callback function is called. |
||
120 | |||
121 | int extended_partition |
||
122 | return 0 on success, other value on error |
||
123 | |||
124 | char *lname |
||
125 | it is the name of the physical disk; for informational purpose only |
||
126 | (for example "hda"). |
||
127 | |||
128 | __dev_t device |
||
129 | it's the device to scan |
||
130 | |||
131 | lodsk_callback_func func |
||
132 | it's the callback function to call when a new partition is found |
||
133 | |||
134 | void *data |
||
135 | this is opaque data passed to the callback function |
||
136 | |||
137 | __blkcnt_t psect |
||
138 | is the starting block (sector) number for this extended partition |
||
139 | |||
140 | __blkcnt_t psize |
||
141 | is the size in blocks of this extended partition |
||
142 | |||
143 | int showinfo |
||
144 | show information with printk() |
||
145 | ++++++++++++++++++++++++++++++++++++++*/ |
||
146 | |||
147 | /* this routine is from Linux 2.2.9 (modificated to run into S.Ha.R.K.) */ |
||
148 | |||
149 | static int extended_partition(char *lname, __dev_t device, |
||
150 | lodsk_callback_func func, void *data, |
||
151 | __blkcnt_t psect, __blkcnt_t psize, |
||
152 | char *infobuffer, int nextid) |
||
153 | { |
||
154 | char name[MAXLODSKNAME]; |
||
155 | struct phpartition *ppar; |
||
156 | struct partition lpar; |
||
157 | struct lodskinfo info; |
||
158 | __blkcnt_t stpsect=psect; |
||
159 | int ret; |
||
160 | int i; |
||
161 | int counter=5; |
||
162 | int first=1; |
||
163 | |||
164 | //if (phdsk_sectorsize(pdisk)!=512) return -1; |
||
165 | |||
166 | for (;;) { |
||
167 | |||
168 | //cprintf("reading block %li\n",(long)psect); |
||
169 | |||
170 | ret=bdev_read(device,psect,buffer); |
||
171 | if (ret) return -1; |
||
172 | //cprintf("read block %li\n",(long)psect); |
||
173 | if (*(__uint16_t*)(buffer+0x1fe)!=MSDOS_LABEL_MAGIC) return -1; |
||
174 | //cprintf("ok sector\n"); |
||
175 | |||
176 | ppar=(struct phpartition*)(buffer+0x1be); |
||
177 | |||
178 | /* |
||
179 | * Usually, the first entry is the real data partition, |
||
180 | * the 2nd entry is the next extended partition, or empty, |
||
181 | * and the 3rd and 4th entries are unused. |
||
182 | * However, DRDOS sometimes has the extended partition as |
||
183 | * the first entry (when the data partition is empty), |
||
184 | * and OS/2 seems to use all four entries. |
||
185 | */ |
||
186 | |||
187 | /* |
||
188 | * First process the data partition(s) |
||
189 | */ |
||
190 | |||
191 | for (i=0; i<4; i++, ppar++) { |
||
192 | partph2lo(ppar,&lpar); |
||
193 | |||
194 | /* |
||
195 | cprintf("-- %i --\n",i+x); |
||
196 | cprintf("c: %4i h: %4i s: %4i\n",lpar.st_cyl,lpar.st_head,lpar.st_sect); |
||
197 | cprintf("c: %4i h: %4i s: %4i\n",lpar.en_cyl,lpar.en_head,lpar.en_sect); |
||
198 | cprintf("sys: %02x relsec: %li num sect: %li\n", |
||
199 | lpar.sys_ind,lpar.rel_sect,lpar.nr_sects); |
||
200 | */ |
||
201 | |||
202 | if (!lpar.nr_sects || is_extended_partition(lpar.sys_ind)) |
||
203 | continue; |
||
204 | |||
205 | /* Check the 3rd and 4th entries - |
||
206 | these sometimes contain random garbage */ |
||
207 | if (i >= 2 |
||
208 | && lpar.rel_sect + lpar.nr_sects > psize |
||
209 | && (psect + lpar.rel_sect < psect || |
||
210 | psect + lpar.rel_sect + lpar.nr_sects > |
||
211 | psect + psize)) |
||
212 | continue; |
||
213 | |||
214 | sprintf(name,"%s%i ",lname,counter++); |
||
215 | |||
216 | info.fs_ind=lpar.sys_ind; |
||
217 | info.start=psect+lpar.rel_sect; |
||
218 | info.size=lpar.nr_sects; |
||
219 | ret=func(nextid++,&info,data); |
||
220 | |||
221 | if (infobuffer!=NULL&&first) strcat(infobuffer,"< "); |
||
222 | first=0; |
||
223 | if (infobuffer) strcat(infobuffer,name); |
||
224 | } |
||
225 | |||
226 | ppar=(struct phpartition*)(buffer+0x1be); |
||
227 | |||
228 | /* |
||
229 | * Next, process the (first) extended partition, if present. |
||
230 | * (So far, there seems to be no reason to make |
||
231 | * extended_partition() recursive and allow a tree |
||
232 | * of extended partitions.) |
||
233 | * It should be a link to the next logical partition. |
||
234 | * Create a minor for this just long enough to get the next |
||
235 | * partition table. The minor will be reused for the next |
||
236 | * data partition. |
||
237 | */ |
||
238 | for (i=0; i<4; i++, ppar++) |
||
239 | if(ppar->nr_sects && is_extended_partition(ppar->sys_ind)) |
||
240 | break; |
||
241 | if (i == 4) |
||
242 | break; /* nothing left to do, go to the end*/ |
||
243 | |||
244 | psect=stpsect+ppar->rel_sect; |
||
245 | psize=ppar->nr_sects; |
||
246 | } |
||
247 | |||
248 | if (infobuffer!=NULL&&!first) strcat(infobuffer,"> "); |
||
249 | return nextid; |
||
250 | } |
||
251 | |||
252 | //extern int ide_check_geometry(int pdisk, __uint8_t *buffer); |
||
253 | |||
254 | /*++++++++++++++++++++++++++++++++++++++ |
||
255 | |||
256 | This function is called to scan a physical hard disk to find its logical |
||
257 | structure (IBM PC hard disk harchitecture is supposed). |
||
258 | |||
259 | int msdos_partition |
||
260 | return 0 on success, other value on error |
||
261 | |||
262 | char *lname |
||
263 | name to use if information is shown (for example "hdc") |
||
264 | |||
265 | __dev_t device |
||
266 | device to scan |
||
267 | |||
268 | lodsk_callback_func func |
||
269 | callback function to call when a partition is found |
||
270 | |||
271 | void *data |
||
272 | opaque data passed to the callback function |
||
273 | |||
274 | int showinfo |
||
275 | is true if informations will be displayed |
||
276 | ++++++++++++++++++++++++++++++++++++++*/ |
||
277 | |||
278 | /* this routine is from Linux 2.2.9 (modificated to run into S.Ha.R.K.) */ |
||
279 | |||
280 | static int ibmpc_arch_scan(char *lname, __dev_t device, |
||
281 | lodsk_callback_func func, |
||
282 | void *data, char *infobuffer) |
||
283 | { |
||
284 | struct lodskinfo info; |
||
285 | char name[MAXLODSKNAME]; |
||
286 | struct phpartition *ppar; |
||
287 | struct partition lpar; |
||
288 | int i; |
||
289 | int ret; |
||
290 | int nextid; |
||
291 | |||
292 | ret=bdev_read(device,0,buffer); |
||
293 | if (ret) { |
||
294 | cprintf("XXXXXXXXXXXXXXXX"); |
||
295 | return -1; |
||
296 | } |
||
297 | |||
298 | //if (phdsk_sectorsize(pdisk)!=512) return -1; |
||
299 | |||
300 | if (*(__uint16_t*)(buffer+0x1fe)!=MSDOS_LABEL_MAGIC) return -1; |
||
301 | |||
302 | ppar=(struct phpartition*)(buffer+0x1be); |
||
303 | |||
304 | nextid=5; |
||
305 | for (i=0;i<4;i++,ppar+=1) { |
||
306 | partph2lo(ppar,&lpar); |
||
307 | |||
308 | /* |
||
309 | cprintf("-- %i --\n",i); |
||
310 | cprintf("c: %4i h: %4i s: %4i\n",lpar.st_cyl,lpar.st_head,lpar.st_sect); |
||
311 | cprintf("c: %4i h: %4i s: %4i\n",lpar.en_cyl,lpar.en_head,lpar.en_sect); |
||
312 | cprintf("sys: %02x relsec: %li num sect: %li\n", |
||
313 | lpar.sys_ind,lpar.rel_sect,lpar.nr_sects); |
||
314 | */ |
||
315 | |||
316 | /* |
||
317 | if (phdsk[pdisk].ide_check_geom&&i==0) { |
||
318 | ide_check_geometry(pdisk,buffer); |
||
319 | } |
||
320 | */ |
||
321 | |||
322 | if (!lpar.nr_sects) continue; |
||
323 | if (is_extended_partition(lpar.sys_ind)) { |
||
324 | nextid=extended_partition(lname,device,func,data, |
||
325 | lpar.rel_sect,lpar.nr_sects,infobuffer,nextid); |
||
326 | if (nextid<0) return -1; |
||
327 | } else { |
||
328 | sprintf(name,"%s%i ",lname,i+1); |
||
329 | |||
330 | info.fs_ind=lpar.sys_ind; |
||
331 | info.start=lpar.rel_sect; |
||
332 | info.size=lpar.nr_sects; |
||
333 | ret=func(i+1,&info,data); |
||
334 | |||
335 | if (infobuffer) strcat(infobuffer,name); |
||
336 | |||
337 | if (ret) return 0; |
||
338 | } |
||
339 | } |
||
340 | |||
341 | return 0; |
||
342 | } |
||
343 | |||
344 | /*++++++++++++++++++++++++++++++++++++++ |
||
345 | |||
346 | This function scan a physical hard disk for logical structure; actually |
||
347 | only IBM PC hard disk architecture is recognized. |
||
348 | |||
349 | int lodsk_scan |
||
350 | return 0 on success, other value on error |
||
351 | |||
352 | __dev_t device |
||
353 | device to scan |
||
354 | |||
355 | lodsk_callback_func func |
||
356 | callback function to call when a new partition is found |
||
357 | |||
358 | void *data |
||
359 | opaque data passed to the callback function |
||
360 | |||
361 | int showinfo |
||
362 | if information must be displayed |
||
363 | |||
364 | char *lname |
||
365 | logical name, for information only (example "hda") |
||
366 | ++++++++++++++++++++++++++++++++++++++*/ |
||
367 | |||
368 | int lodsk_scan(__dev_t device, lodsk_callback_func func, |
||
369 | void *data, int showinfo, char *lname) |
||
370 | { |
||
371 | char buffer[1024]; /* DANGER!!! */ |
||
372 | int ret; |
||
373 | |||
374 | if (showinfo) sprintf(buffer,"%s: ",lname); |
||
375 | ret=ibmpc_arch_scan(lname,device,func,data,showinfo?buffer:NULL); |
||
376 | if (showinfo) printk(KERN_INFO "%s",buffer); |
||
377 | return ret; |
||
378 | } |
||
379 | |||
380 | |||
381 |