source: rtems/cpukit/libblock/src/ide_part_table.c @ 5b38506

4.104.114.84.9
Last change on this file since 5b38506 was 5b38506, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 4, 2003 at 6:54:04 PM

2003-09-04 Joel Sherrill <joel@…>

  • include/rtems/ide_part_table.h, src/ata.c, src/ide_part_table.c: URL for license changed.
  • Property mode set to 100644
File size: 14.0 KB
Line 
1/*****************************************************************************
2 *
3 * ide_part_table.c
4 *
5 * The implementation of library supporting "MS-DOS-style" partition table
6 *
7 *
8 * Copyright (C) 2002 OKTET Ltd., St.-Petersburg, Russia
9 *
10 * Author: Konstantin Abramenko <Konstantin.Abramenko@oktet.ru>
11 *         Alexander Kukuta <Alexander.Kukuta@oktet.ru>
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
15 *  http://www.rtems.com/license/LICENSE.
16 *
17 * $Id$
18 *
19 *****************************************************************************/
20
21#include <rtems/ide_part_table.h>
22#include <string.h>
23
24/*
25 * get_sector --
26 *      gets sector from the disk
27 *
28 * PARAMETERS:
29 *      dev        - device number
30 *      sector_num - number of sector to read
31 *      sector     - returned pointer to pointer to allocated
32 *                   sector_data_t structure
33 *
34 * RETURNS:
35 *      RTEMS_SUCCESSFUL, if success;
36 *      RTEMS_NO_MEMORY, if canot allocate memory for sector data;
37 *      other error codes returned by rtems_bdbuf_read().
38 *
39 * NOTES:
40 *      get_sector() operates with device via bdbuf library,
41 *      and does not support devices with sector size other than 512 bytes
42 */
43static rtems_status_code
44get_sector(dev_t dev, unsigned32 sector_num, sector_data_t **sector) 
45{
46    sector_data_t      *s;
47    bdbuf_buffer       *buf;
48    rtems_status_code   rc;
49   
50    if (sector == NULL)
51    {
52        return RTEMS_INTERNAL_ERROR;
53    }
54
55    s = (sector_data_t *) malloc(sizeof(sector_data_t) + RTEMS_IDE_SECTOR_SIZE);
56    if (s == NULL)
57    {
58        return RTEMS_NO_MEMORY;
59    }
60   
61    rc = rtems_bdbuf_read(dev, sector_num, &buf);
62    if (rc != RTEMS_SUCCESSFUL)
63    {
64        free(s);
65        return rc;
66    }
67   
68    memcpy(s->data, buf->buffer, RTEMS_IDE_SECTOR_SIZE);
69    s->sector_num = sector_num;
70
71    *sector = s;
72   
73    rtems_bdbuf_release(buf);
74   
75    return RTEMS_SUCCESSFUL;
76}
77
78
79/*
80 * msdos_signature_check --
81 *      checks if the partition table sector has msdos signature
82 *
83 * PARAMETERS:
84 *      sector - sector to check
85 *
86 * RETURNS:
87 *      TRUE if sector has msdos signature, FALSE otherwise
88 */
89static rtems_boolean
90msdos_signature_check (sector_data_t *sector) 
91{
92    unsigned8 *p = sector->data + RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_OFFSET;
93
94    return ((p[0] == RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_DATA1) &&
95            (p[1] == RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_DATA2));
96}
97
98
99/*
100 * is_extended --
101 *      checks if the partition type is extended
102 *
103 * PARAMETERS:
104 *      type - type of partition to check
105 *
106 * RETURNS:
107 *      TRUE if partition type is extended, FALSE otherwise
108 */
109static rtems_boolean
110is_extended(unsigned8 type) 
111{
112    return ((type == EXTENDED_PARTITION) || (type == LINUX_EXTENDED));
113}
114
115/*
116 * is_fat_partition --
117 *      checks if the partition type is defined for FAT
118 *
119 * PARAMETERS:
120 *      type - type of partition to check
121 *
122 * RETURNS:
123 *      TRUE if partition type is extended, FALSE otherwise
124 */
125static rtems_boolean
126is_fat_partition(unsigned8 type) 
127{
128  static const unsigned8 fat_part_types[] = {
129    DOS_FAT12_PARTITION,DOS_FAT16_PARTITION,
130    DOS_P32MB_PARTITION,
131    FAT32_PARTITION    ,FAT32_LBA_PARTITION,
132    FAT16_LBA_PARTITION
133  };
134
135  return (NULL != memchr(fat_part_types,type,sizeof(fat_part_types)));
136}
137
138
139/*
140 * data_to_part_desc --
141 *      parses raw partition table sector data
142 *      to partition description structure
143 *
144 * PARAMETERS:
145 *      data          - raw partition table sector data
146 *      new_part_desc - pointer to returned partition description structure
147 *
148 * RETURNS:
149 *      RTEMS_SUCCESSFUL, if success;
150 *      RTEMS_NO_MEMOTY, if cannot allocate memory for part_desc_t strucure;
151 *      RTEMS_INTERNAL_ERROR, if other error occurs.
152 */
153static rtems_status_code
154data_to_part_desc(unsigned8 *data, part_desc_t **new_part_desc)
155{
156    part_desc_t *part_desc;
157    unsigned32   temp;
158
159    if (new_part_desc == NULL)
160    {
161        return RTEMS_INTERNAL_ERROR;
162    }
163   
164    *new_part_desc = NULL;
165
166    if ((part_desc = calloc(1, sizeof(part_desc_t))) == NULL)
167    {
168        return RTEMS_NO_MEMORY;
169    }
170
171    part_desc->bootable = *(data + RTEMS_IDE_PARTITION_BOOTABLE_OFFSET);
172    part_desc->sys_type = *(data + RTEMS_IDE_PARTITION_SYS_TYPE_OFFSET);
173
174    /* read the offset start position and partition size in sectors */
175
176    /* due to incorrect data alignment one have to align data first */
177    memcpy(&temp, data + RTEMS_IDE_PARTITION_START_OFFSET, sizeof(unsigned32));
178    part_desc->start = LE_TO_CPU_U32(temp);
179
180    memcpy(&temp, data + RTEMS_IDE_PARTITION_SIZE_OFFSET, sizeof(unsigned32));
181    part_desc->size = LE_TO_CPU_U32(temp);
182
183    /*
184     * use partitions that are
185     * - extended
186     * or
187     * - FAT type and non-zero
188     */
189    if (is_extended(part_desc->sys_type) ||
190        ((is_fat_partition(part_desc->sys_type)) && (part_desc->size != 0))) {
191      *new_part_desc = part_desc;
192    }
193    else { 
194      /* empty partition */
195      free(part_desc);
196    }
197    return RTEMS_SUCCESSFUL;
198}
199
200
201/*
202 * read_extended_partition --
203 *      recursively reads extended partition sector from the device
204 *      and constructs the partition table tree
205 *
206 * PARAMETERS:
207 *      start    - start sector of primary extended partition, used for
208 *                 calculation of absolute partition sector address
209 *      ext_part - description of extended partition to process
210 *
211 * RETURNS:
212 *      RTEMS_SUCCESSFUL if success,
213 *      RTEMS_NO_MEMOTY if cannot allocate memory for part_desc_t strucure,
214 *      RTEMS_INTERNAL_ERROR if other error occurs.
215 */
216static rtems_status_code
217read_extended_partition(unsigned32 start, part_desc_t *ext_part) 
218{
219    int                 i;
220    dev_t               dev;
221    sector_data_t      *sector;
222    unsigned32          here;
223    unsigned8          *data;
224    part_desc_t        *new_part_desc;
225    rtems_status_code   rc;
226
227    if ((ext_part == NULL) || (ext_part->disk_desc == NULL))
228    {
229        return RTEMS_INTERNAL_ERROR;
230    }
231   
232    dev = ext_part->disk_desc->dev;
233
234    /* get start sector of current extended partition */
235    here = ext_part->start;
236
237    /* get first extended partition sector */
238
239    rc = get_sector(dev, here, &sector);
240    if (rc != RTEMS_SUCCESSFUL)
241    {
242        return rc;
243    }
244
245    if (!msdos_signature_check(sector))
246    {
247        return RTEMS_INTERNAL_ERROR;
248    }
249
250    /* read and process up to 4 logical partition descriptors */
251
252    data = sector->data + RTEMS_IDE_PARTITION_TABLE_OFFSET;
253
254    for (i = 0; i < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER; i++) 
255    {
256        /* if data_to_part_desc fails skip this partition
257         * and parse the next one
258         */
259        rc = data_to_part_desc(data, &new_part_desc);
260        if (rc != RTEMS_SUCCESSFUL)
261        {
262            free(sector);
263            return rc;
264        }
265       
266        if (new_part_desc == NULL)
267        {
268            data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE;
269            continue;
270        }
271
272        ext_part->sub_part[i] = new_part_desc;
273        new_part_desc->ext_part = ext_part;
274        new_part_desc->disk_desc = ext_part->disk_desc;
275
276        if (is_extended(new_part_desc->sys_type)) 
277        {
278            new_part_desc->log_id = EMPTY_PARTITION;
279            new_part_desc->start += start;
280            read_extended_partition(start, new_part_desc); 
281        }
282        else 
283        {
284            disk_desc_t *disk_desc = new_part_desc->disk_desc;
285            disk_desc->partitions[disk_desc->last_log_id] = new_part_desc;
286            new_part_desc->log_id = ++disk_desc->last_log_id;
287            new_part_desc->start += here;
288            new_part_desc->end = new_part_desc->start + new_part_desc->size - 1;
289        }
290        data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE;
291    }
292
293    free(sector);
294   
295    return RTEMS_SUCCESSFUL;
296}
297
298
299/*
300 * read_mbr --
301 *      reads Master Boot Record (sector 0) of physical device and
302 *      constructs disk description structure
303 *
304 * PARAMETERS:
305 *      disk_desc - returned disc description structure
306 *
307 * RETURNS:
308 *      RTEMS_SUCCESSFUL if success,
309 *      RTEMS_INTERNAL_ERROR otherwise
310 */
311static rtems_status_code
312read_mbr(disk_desc_t *disk_desc) 
313{
314    int                 part_num;
315    sector_data_t      *sector;
316    part_desc_t        *part_desc;
317    unsigned8          *data;
318    rtems_status_code   rc;
319    dev_t               dev = disk_desc->dev;
320
321    /* get MBR sector */
322    rc = get_sector(dev, 0, &sector);
323    if (rc != RTEMS_SUCCESSFUL)
324    {
325        return rc;
326    }
327
328    /* check if the partition table structure is MS-DOS style */
329    if (!msdos_signature_check(sector))
330    {
331        return RTEMS_INTERNAL_ERROR;
332    }
333
334    /* read and process 4 primary partition descriptors */
335
336    data = sector->data + RTEMS_IDE_PARTITION_TABLE_OFFSET;
337
338    for (part_num = 0;
339         part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
340         part_num++)
341    {
342        rc = data_to_part_desc(data, &part_desc);
343        if (rc != RTEMS_SUCCESSFUL)
344        {
345            free(sector);
346            return rc;
347        }
348
349        if (part_desc != NULL) 
350        {
351            part_desc->log_id = part_num + 1;
352            part_desc->disk_desc = disk_desc;
353            part_desc->end = part_desc->start + part_desc->size - 1;
354            disk_desc->partitions[part_num] = part_desc;
355        } 
356        else
357        {
358            disk_desc->partitions[part_num] = NULL;
359        }
360
361        data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE;
362    }
363
364    free(sector);
365   
366    disk_desc->last_log_id = RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
367
368    /* There cannot be more than one extended partition,
369       but we are to process each primary partition */
370    for (part_num = 0;
371         part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
372         part_num++)
373    {
374        if (is_extended(disk_desc->partitions[part_num]->sys_type))
375        {
376            read_extended_partition(disk_desc->partitions[part_num]->start,
377                                    disk_desc->partitions[part_num]);
378        }
379    }
380
381    return RTEMS_SUCCESSFUL;
382}
383
384
385/*
386 * partition free --
387 *      frees partition description structure
388 *
389 * PARAMETERS:
390 *      part_desc - returned disc description structure
391 *
392 * RETURNS:
393 *      N/A
394 */
395static void
396partition_free(part_desc_t *part_desc)
397{
398    int part_num;
399
400    if (part_desc == NULL)
401        return;
402   
403    if (is_extended(part_desc->sys_type))
404    {
405        for (part_num = 0;
406             part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
407             part_num++)
408        {
409            partition_free(part_desc->sub_part[part_num]);
410        }
411    }
412   
413    free(part_desc);
414}
415
416
417/*
418 * rtems_ide_part_table_free - frees disk descriptor structure
419 *
420 * PARAMETERS:
421 *      disk_desc - disc descriptor structure to free
422 *
423 * RETURNS:
424 *      N/A
425 */
426void
427rtems_ide_part_table_free(disk_desc_t *disk_desc)
428{
429    int part_num;
430
431    for (part_num = 0; part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER; part_num++)
432    {
433        partition_free(disk_desc->partitions[part_num]);
434    }
435   
436    free(disk_desc);
437}
438
439
440/*
441 * rtems_ide_part_table_get - reads partition table structure from the device
442 *                            and creates disk description structure
443 *
444 * PARAMETERS:
445 *      dev_name - path to physical device in /dev filesystem
446 *      disk_desc       - returned disc description structure
447 *
448 * RETURNS:
449 *      RTEMS_SUCCESSFUL if success,
450 *      RTEMS_INTERNAL_ERROR otherwise
451 */
452rtems_status_code
453rtems_ide_part_table_get(const char *dev_name, disk_desc_t *disk_desc)
454{
455    struct stat         dev_stat;
456    rtems_status_code   rc;
457
458    rc = stat(dev_name, &dev_stat);
459    if (rc != RTEMS_SUCCESSFUL)
460    {
461        return RTEMS_INTERNAL_ERROR;
462    }
463
464    strncpy (disk_desc->dev_name, dev_name, 15);
465    disk_desc->dev = dev_stat.st_dev;
466    disk_desc->sector_size = (dev_stat.st_blksize) ? dev_stat.st_blksize :
467                                              RTEMS_IDE_SECTOR_SIZE;
468
469    rc = read_mbr(disk_desc);
470
471    return rc;
472}
473
474
475/*
476 * rtems_ide_part_table_initialize - initializes logical devices
477 *                                   on the physical IDE drive
478 *
479 * PARAMETERS:
480 *      dev_name - path to physical device in /dev filesystem
481 *
482 * RETURNS:
483 *      RTEMS_SUCCESSFUL if success,
484 *      RTEMS_NO_MEMOTY if cannot have not enough memory,
485 *      RTEMS_INTERNAL_ERROR if other error occurs.
486 */
487rtems_status_code
488rtems_ide_part_table_initialize(char *dev_name)
489{
490    int                         part_num;
491    dev_t                       dev;
492    disk_desc_t                *disk_desc;
493    rtems_device_major_number   major;
494    rtems_device_minor_number   minor;
495    rtems_status_code           rc;
496    part_desc_t                *part_desc;
497
498    /* logical device name /dev/hdxyy */
499    char                        name[RTEMS_IDE_PARTITION_DEV_NAME_LENGTH_MAX];
500
501    disk_desc = (disk_desc_t *) calloc(1, sizeof(disk_desc_t));
502    if (disk_desc == NULL)
503    {
504        return RTEMS_NO_MEMORY;
505    }
506   
507    /* get partition table */
508    rc = rtems_ide_part_table_get(dev_name, disk_desc);
509    if (rc != RTEMS_SUCCESSFUL)
510    {
511        return rc;
512    }
513
514    /* To avoid device numbers conflicts we have to use for logic disk the same
515     * device major number as ATA device has, and minor number that equals to
516     * sum of logic disk partition number and the minor number of physical disk
517     */
518
519    rtems_filesystem_split_dev_t (disk_desc->dev, major, minor);
520
521    /* create logical disks on the physical one */
522    for (part_num = 0; part_num < disk_desc->last_log_id; part_num++)
523    {
524        sprintf(name, "%s%d", dev_name, part_num + 1);
525        dev = rtems_filesystem_make_dev_t(major, ++minor);
526
527        part_desc = disk_desc->partitions[part_num];
528        if (part_desc == NULL)
529        {
530            continue;
531        }
532
533        rc = rtems_disk_create_log(dev, disk_desc->dev, part_desc->start,
534                                   part_desc->size, name);
535        if (rc != RTEMS_SUCCESSFUL)
536        {
537            printf("Cannot create device %s, error code %d\n", name, rc);
538            continue;
539        }
540    }
541
542    rtems_ide_part_table_free(disk_desc);
543
544    return RTEMS_SUCCESSFUL;
545}
Note: See TracBrowser for help on using the repository browser.