source: rtems/cpukit/libblock/src/ide_part_table.c @ a1f1011

4.104.114.84.95
Last change on this file since a1f1011 was ef142d7, checked in by Joel Sherrill <joel.sherrill@…>, on 10/28/02 at 14:00:43

2002-10-28 Eugeny S. Mints <Eugeny.Mints@…>

  • Added ATA support.
  • include/rtems/blkdev.h: Added last IO status.
  • include/rtems/ata.h, include/rtems/ata_internal.h, include/rtems/ide_part_table.h, src/ata.c, src/ide_part_table.c: New files.
  • Property mode set to 100644
File size: 13.4 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.OARcorp.com/rtems/license.html.
16 *
17 * $Id$
18 *
19 *****************************************************************************/
20
21#include <rtems/ide_part_table.h>
22
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/*
117 * data_to_part_desc --
118 *      parses raw partition table sector data
119 *      to partition description structure
120 *
121 * PARAMETERS:
122 *      data          - raw partition table sector data
123 *      new_part_desc - pointer to returned partition description structure
124 *
125 * RETURNS:
126 *      RTEMS_SUCCESSFUL, if success;
127 *      RTEMS_NO_MEMOTY, if cannot allocate memory for part_desc_t strucure;
128 *      RTEMS_INTERNAL_ERROR, if other error occurs.
129 */
130static rtems_status_code
131data_to_part_desc(unsigned8 *data, part_desc_t **new_part_desc)
132{
133    part_desc_t *part_desc;
134    unsigned32   temp;
135
136    if (new_part_desc == NULL)
137    {
138        return RTEMS_INTERNAL_ERROR;
139    }
140   
141    *new_part_desc = NULL;
142
143    if ((part_desc = calloc(1, sizeof(part_desc_t))) == NULL)
144    {
145        return RTEMS_NO_MEMORY;
146    }
147
148    part_desc->bootable = *(data + RTEMS_IDE_PARTITION_BOOTABLE_OFFSET);
149    part_desc->sys_type = *(data + RTEMS_IDE_PARTITION_SYS_TYPE_OFFSET);
150
151    /* read the offset start position and partition size in sectors */
152
153    /* due to incorrect data alignment one have to align data first */
154    memcpy(&temp, data + RTEMS_IDE_PARTITION_START_OFFSET, sizeof(unsigned32));
155    part_desc->start = LE_TO_CPU_U32(temp);
156
157    memcpy(&temp, data + RTEMS_IDE_PARTITION_SIZE_OFFSET, sizeof(unsigned32));
158    part_desc->size = LE_TO_CPU_U32(temp);
159
160    if ((part_desc->sys_type == EMPTY_PARTITION) ||
161        ((part_desc->size == 0) && (!is_extended(part_desc->sys_type))))
162    {
163        /* empty partition */
164        free(part_desc);
165        return RTEMS_SUCCESSFUL;
166    }
167   
168    *new_part_desc = part_desc;
169
170    return RTEMS_SUCCESSFUL;
171}
172
173
174/*
175 * read_extended_partition --
176 *      recursively reads extended partition sector from the device
177 *      and constructs the partition table tree
178 *
179 * PARAMETERS:
180 *      start    - start sector of primary extended partition, used for
181 *                 calculation of absolute partition sector address
182 *      ext_part - description of extended partition to process
183 *
184 * RETURNS:
185 *      RTEMS_SUCCESSFUL if success,
186 *      RTEMS_NO_MEMOTY if cannot allocate memory for part_desc_t strucure,
187 *      RTEMS_INTERNAL_ERROR if other error occurs.
188 */
189static rtems_status_code
190read_extended_partition(unsigned32 start, part_desc_t *ext_part)
191{
192    int                 i;
193    dev_t               dev;
194    sector_data_t      *sector;
195    unsigned32          here;
196    unsigned8          *data;
197    part_desc_t        *new_part_desc;
198    rtems_status_code   rc;
199
200    if ((ext_part == NULL) || (ext_part->disk_desc == NULL))
201    {
202        return RTEMS_INTERNAL_ERROR;
203    }
204   
205    dev = ext_part->disk_desc->dev;
206
207    /* get start sector of current extended partition */
208    here = ext_part->start;
209
210    /* get first extended partition sector */
211
212    rc = get_sector(dev, here, &sector);
213    if (rc != RTEMS_SUCCESSFUL)
214    {
215        return rc;
216    }
217
218    if (!msdos_signature_check(sector))
219    {
220        return RTEMS_INTERNAL_ERROR;
221    }
222
223    /* read and process up to 4 logical partition descriptors */
224
225    data = sector->data + RTEMS_IDE_PARTITION_TABLE_OFFSET;
226
227    for (i = 0; i < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER; i++)
228    {
229        /* if data_to_part_desc fails skip this partition
230         * and parse the next one
231         */
232        rc = data_to_part_desc(data, &new_part_desc);
233        if (rc != RTEMS_SUCCESSFUL)
234        {
235            free(sector);
236            return rc;
237        }
238       
239        if (new_part_desc == NULL)
240        {
241            data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE;
242            continue;
243        }
244
245        ext_part->sub_part[i] = new_part_desc;
246        new_part_desc->ext_part = ext_part;
247        new_part_desc->disk_desc = ext_part->disk_desc;
248
249        if (is_extended(new_part_desc->sys_type))
250        {
251            new_part_desc->log_id = EMPTY_PARTITION;
252            new_part_desc->start += start;
253            read_extended_partition(start, new_part_desc);
254        }
255        else
256        {
257            disk_desc_t *disk_desc = new_part_desc->disk_desc;
258            disk_desc->partitions[disk_desc->last_log_id] = new_part_desc;
259            new_part_desc->log_id = ++disk_desc->last_log_id;
260            new_part_desc->start += here;
261            new_part_desc->end = new_part_desc->start + new_part_desc->size - 1;
262        }
263        data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE;
264    }
265
266    free(sector);
267   
268    return RTEMS_SUCCESSFUL;
269}
270
271
272/*
273 * read_mbr --
274 *      reads Master Boot Record (sector 0) of physical device and
275 *      constructs disk description structure
276 *
277 * PARAMETERS:
278 *      disk_desc - returned disc description structure
279 *
280 * RETURNS:
281 *      RTEMS_SUCCESSFUL if success,
282 *      RTEMS_INTERNAL_ERROR otherwise
283 */
284static rtems_status_code
285read_mbr(disk_desc_t *disk_desc)
286{
287    int                 part_num;
288    sector_data_t      *sector;
289    part_desc_t        *part_desc;
290    unsigned8          *data;
291    rtems_status_code   rc;
292    dev_t               dev = disk_desc->dev;
293
294    /* get MBR sector */
295    rc = get_sector(dev, 0, &sector);
296    if (rc != RTEMS_SUCCESSFUL)
297    {
298        return rc;
299    }
300
301    /* check if the partition table structure is MS-DOS style */
302    if (!msdos_signature_check(sector))
303    {
304        return RTEMS_INTERNAL_ERROR;
305    }
306
307    /* read and process 4 primary partition descriptors */
308
309    data = sector->data + RTEMS_IDE_PARTITION_TABLE_OFFSET;
310
311    for (part_num = 0;
312         part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
313         part_num++)
314    {
315        rc = data_to_part_desc(data, &part_desc);
316        if (rc != RTEMS_SUCCESSFUL)
317        {
318            free(sector);
319            return rc;
320        }
321
322        if (part_desc != NULL)
323        {
324            part_desc->log_id = part_num + 1;
325            part_desc->disk_desc = disk_desc;
326            part_desc->end = part_desc->start + part_desc->size - 1;
327            disk_desc->partitions[part_num] = part_desc;
328        }
329        else
330        {
331            disk_desc->partitions[part_num] = NULL;
332        }
333
334        data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE;
335    }
336
337    free(sector);
338   
339    disk_desc->last_log_id = RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
340
341    /* There cannot be more than one extended partition,
342       but we are to process each primary partition */
343    for (part_num = 0;
344         part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
345         part_num++)
346    {
347        if (is_extended(disk_desc->partitions[part_num]->sys_type))
348        {
349            read_extended_partition(disk_desc->partitions[part_num]->start,
350                                    disk_desc->partitions[part_num]);
351        }
352    }
353
354    return RTEMS_SUCCESSFUL;
355}
356
357
358/*
359 * partition free --
360 *      frees partition description structure
361 *
362 * PARAMETERS:
363 *      part_desc - returned disc description structure
364 *
365 * RETURNS:
366 *      N/A
367 */
368static void
369partition_free(part_desc_t *part_desc)
370{
371    int part_num;
372
373    if (part_desc == NULL)
374        return;
375   
376    if (is_extended(part_desc->sys_type))
377    {
378        for (part_num = 0;
379             part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
380             part_num++)
381        {
382            partition_free(part_desc->sub_part[part_num]);
383        }
384    }
385   
386    free(part_desc);
387}
388
389
390/*
391 * rtems_ide_part_table_free - frees disk descriptor structure
392 *
393 * PARAMETERS:
394 *      disk_desc - disc descriptor structure to free
395 *
396 * RETURNS:
397 *      N/A
398 */
399void
400rtems_ide_part_table_free(disk_desc_t *disk_desc)
401{
402    int part_num;
403
404    for (part_num = 0; part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER; part_num++)
405    {
406        partition_free(disk_desc->partitions[part_num]);
407    }
408   
409    free(disk_desc);
410}
411
412
413/*
414 * rtems_ide_part_table_get - reads partition table structure from the device
415 *                            and creates disk description structure
416 *
417 * PARAMETERS:
418 *      dev_name - path to physical device in /dev filesystem
419 *      disk_desc       - returned disc description structure
420 *
421 * RETURNS:
422 *      RTEMS_SUCCESSFUL if success,
423 *      RTEMS_INTERNAL_ERROR otherwise
424 */
425rtems_status_code
426rtems_ide_part_table_get(const char *dev_name, disk_desc_t *disk_desc)
427{
428    struct stat         dev_stat;
429    rtems_status_code   rc;
430
431    rc = stat(dev_name, &dev_stat);
432    if (rc != RTEMS_SUCCESSFUL)
433    {
434        return RTEMS_INTERNAL_ERROR;
435    }
436
437    strncpy (disk_desc->dev_name, dev_name, 15);
438    disk_desc->dev = dev_stat.st_dev;
439    disk_desc->sector_size = (dev_stat.st_blksize) ? dev_stat.st_blksize :
440                                              RTEMS_IDE_SECTOR_SIZE;
441
442    rc = read_mbr(disk_desc);
443
444    return rc;
445}
446
447
448/*
449 * rtems_ide_part_table_initialize - initializes logical devices
450 *                                   on the physical IDE drive
451 *
452 * PARAMETERS:
453 *      dev_name - path to physical device in /dev filesystem
454 *
455 * RETURNS:
456 *      RTEMS_SUCCESSFUL if success,
457 *      RTEMS_NO_MEMOTY if cannot have not enough memory,
458 *      RTEMS_INTERNAL_ERROR if other error occurs.
459 */
460rtems_status_code
461rtems_ide_part_table_initialize(char *dev_name)
462{
463    int                         part_num;
464    dev_t                       dev;
465    disk_desc_t                *disk_desc;
466    rtems_device_major_number   major;
467    rtems_device_minor_number   minor;
468    rtems_status_code           rc;
469    part_desc_t                *part_desc;
470
471    /* logical device name /dev/hdxyy */
472    char                        name[RTEMS_IDE_PARTITION_DEV_NAME_LENGTH_MAX];
473
474    disk_desc = (disk_desc_t *) calloc(1, sizeof(disk_desc_t));
475    if (disk_desc == NULL)
476    {
477        return RTEMS_NO_MEMORY;
478    }
479   
480    /* get partition table */
481    rc = rtems_ide_part_table_get(dev_name, disk_desc);
482    if (rc != RTEMS_SUCCESSFUL)
483    {
484        return rc;
485    }
486
487    /* To avoid device numbers conflicts we have to use for logic disk the same
488     * device major number as ATA device has, and minor number that equals to
489     * sum of logic disk partition number and the minor number of physical disk
490     */
491
492    rtems_filesystem_split_dev_t (disk_desc->dev, major, minor);
493
494    /* create logical disks on the physical one */
495    for (part_num = 0; part_num < disk_desc->last_log_id; part_num++)
496    {
497        sprintf(name, "%s%d", dev_name, part_num + 1);
498        dev = rtems_filesystem_make_dev_t(major, ++minor);
499
500        part_desc = disk_desc->partitions[part_num];
501        if (part_desc == NULL)
502        {
503            continue;
504        }
505
506        rc = rtems_disk_create_log(dev, disk_desc->dev, part_desc->start,
507                                   part_desc->size, name);
508        if (rc != RTEMS_SUCCESSFUL)
509        {
510            printf("Cannot create device %s, error code %d\n", name, rc);
511            continue;
512        }
513    }
514
515    rtems_ide_part_table_free(disk_desc);
516
517    return RTEMS_SUCCESSFUL;
518}
Note: See TracBrowser for help on using the repository browser.