source: rtems/cpukit/libblock/src/diskdevs.c @ 006fa1ef

4.104.114.84.9
Last change on this file since 006fa1ef was 006fa1ef, checked in by Ralf Corsepius <ralf.corsepius@…>, on Nov 20, 2003 at 12:14:50 PM

2003-11-20 Ralf Corsepius <corsepiu@…>

  • Makefile.am: AM_CPPFLAGS += -I$(top_builddir). Use AM_CPPFLAGS instead of AM_CFLAGS.
  • src/ata.c: Include config.h.
  • src/bdbuf.c: Ditto.
  • src/blkdev.c: Ditto.
  • src/diskdevs.c: Ditto.
  • src/ide_part_table.c: Ditto.
  • src/ramdisk.c: Ditto.
  • Property mode set to 100644
File size: 17.2 KB
Line 
1/*
2 * diskdevs.c - Physical and logical block devices (disks) support
3 *
4 * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
5 * Author: Victor V. Vengerov <vvv@oktet.ru>
6 *
7 * @(#) $Id$
8 */
9
10#if HAVE_CONFIG_H
11#include "config.h"
12#endif
13
14#include <rtems.h>
15#include <rtems/libio.h>
16#include <stdlib.h>
17#include <unistd.h>     /* unlink */
18#include <string.h>
19
20#include "rtems/diskdevs.h"
21#include "rtems/bdbuf.h"
22
23#define DISKTAB_INITIAL_SIZE 32
24
25/* Table of disk devices having the same major number */
26struct disk_device_table {
27    disk_device **minor; /* minor-indexed disk device table */
28    int size;            /* Number of entries in the table */
29};
30
31/* Pointer to [major].minor[minor] indexed array of disk devices */
32static struct disk_device_table *disktab;
33
34/* Number of allocated entries in disktab table */
35static int disktab_size;
36
37/* Mutual exclusion semaphore for disk devices table */
38static rtems_id diskdevs_mutex;
39
40/* Flag meaning that disk I/O, buffering etc. already has been initialized. */
41static boolean disk_io_initialized = FALSE;
42
43/* diskdevs data structures protection flag.
44 * Normally, only table lookup operations performed. It is quite fast, so
45 * it is possible to done lookups when interrupts are disabled, avoiding
46 * obtaining the semaphore. This flags sets immediately after entering in
47 * mutex-protected section and cleared before leaving this section in
48 * "big" primitives like add/delete new device etc. Lookup function first
49 * disable interrupts and check this flag. If it is set, lookup function
50 * will be blocked on semaphore and lookup operation will be performed in
51 * semaphore-protected code. If it is not set (very-very frequent case),
52 * we can do lookup safely, enable interrupts and return result.
53 */
54static volatile rtems_boolean diskdevs_protected;
55
56/* create_disk_entry --
57 *     Return pointer to the disk_entry structure for the specified device, or
58 *     create one if it is not exists.
59 *
60 * PARAMETERS:
61 *     dev - device id (major, minor)
62 *
63 * RETURNS:
64 *     pointer to the disk device descirptor entry, or NULL if no memory
65 *     available for its creation.
66 */
67static disk_device *
68create_disk_entry(dev_t dev)
69{
70    rtems_device_major_number major;
71    rtems_device_minor_number minor;
72    struct disk_device **d;
73
74    rtems_filesystem_split_dev_t (dev, major, minor);
75   
76    if (major >= disktab_size)
77    {
78        struct disk_device_table *p;
79        int newsize;
80        int i;
81        newsize = disktab_size * 2;
82        if (major >= newsize)
83            newsize = major + 1;
84        p = realloc(disktab, sizeof(struct disk_device_table) * newsize);
85        if (p == NULL)
86            return NULL;
87        p += disktab_size;
88        for (i = disktab_size; i < newsize; i++, p++)
89        {
90            p->minor = NULL;
91            p->size = 0;
92        }
93        disktab_size = newsize;
94    }
95   
96    if ((disktab[major].minor == NULL) ||
97        (minor >= disktab[major].size))
98    {
99        int newsize;
100        disk_device **p;
101        int i;
102        int s = disktab[major].size;
103       
104        if (s == 0)
105            newsize = DISKTAB_INITIAL_SIZE;
106        else
107            newsize = s * 2;
108        if (minor >= newsize)
109            newsize = minor + 1;
110       
111        p = realloc(disktab[major].minor, sizeof(disk_device *) * newsize);
112        if (p == NULL)
113            return NULL;
114        disktab[major].minor = p;
115        p += s;
116        for (i = s; i < newsize; i++, p++)
117            *p = NULL;
118        disktab[major].size = newsize;
119    }
120   
121    d = disktab[major].minor + minor;
122    if (*d == NULL)
123    {
124        *d = calloc(1, sizeof(disk_device));
125    }
126    return *d;
127}
128
129/* get_disk_entry --
130 *     Get disk device descriptor by device number.
131 *
132 * PARAMETERS:
133 *     dev - block device number
134 *
135 * RETURNS:
136 *     Pointer to the disk device descriptor corresponding to the specified
137 *     device number, or NULL if disk device with such number not exists.
138 */
139static inline disk_device *
140get_disk_entry(dev_t dev)
141{
142    rtems_device_major_number major;
143    rtems_device_minor_number minor;
144    struct disk_device_table *dtab;
145
146    rtems_filesystem_split_dev_t (dev, major, minor);
147   
148    if ((major >= disktab_size) || (disktab == NULL))
149        return NULL;
150       
151    dtab = disktab + major;
152   
153    if ((minor >= dtab->size) || (dtab->minor == NULL))
154        return NULL;
155   
156    return dtab->minor[minor];
157}
158
159/* create_disk --
160 *     Check that disk entry for specified device number is not defined
161 *     and create it.
162 *
163 * PARAMETERS:
164 *     dev        - device identifier (major, minor numbers)
165 *     name       - character name of device (e.g. /dev/hda)
166 *     disdev     - placeholder for pointer to created disk descriptor
167 *
168 * RETURNS:
169 *     RTEMS_SUCCESSFUL if disk entry successfully created, or
170 *     error code if error occured (device already registered,
171 *     no memory available).
172 */
173static rtems_status_code
174create_disk(dev_t dev, char *name, disk_device **diskdev)
175{
176    disk_device *dd;
177    char *n;
178   
179    dd = get_disk_entry(dev);
180    if (dd != NULL)
181    {
182        return RTEMS_RESOURCE_IN_USE;
183    }
184   
185    if (name == NULL)
186    {
187        n = NULL;
188    }
189    else
190    {
191        int nlen = strlen(name) + 1;
192        n = malloc(nlen);
193        if (n == NULL)
194            return RTEMS_NO_MEMORY;
195        strncpy(n, name, nlen);
196    }
197   
198    dd = create_disk_entry(dev);
199    if (dd == NULL)
200    {
201        free(n);
202        return RTEMS_NO_MEMORY;
203    }
204   
205    dd->dev = dev;
206    dd->name = n;
207   
208    *diskdev = dd;
209   
210    return RTEMS_SUCCESSFUL;
211}
212
213/* rtems_disk_create_phys --
214 *     Create physical disk entry. This function usually invoked from
215 *     block device driver initialization code when physical device
216 *     detected in the system. Device driver should provide ioctl handler
217 *     to allow block device access operations. This primitive will register
218 *     device in rtems (invoke rtems_io_register_name).
219 *
220 * PARAMETERS:
221 *     dev        - device identifier (major, minor numbers)
222 *     block_size - size of disk block (minimum data transfer unit); must be
223 *                  power of 2
224 *     disk_size  - number of blocks on device
225 *     handler    - IOCTL handler (function providing basic block input/output
226 *                  request handling BIOREQUEST and other device management
227 *                  operations)
228 *     name       - character name of device (e.g. /dev/hda)
229 *
230 * RETURNS:
231 *     RTEMS_SUCCESSFUL if information about new physical disk added, or
232 *     error code if error occured (device already registered, wrong block
233 *     size value, no memory available).
234 */
235rtems_status_code
236rtems_disk_create_phys(dev_t dev, int block_size, int disk_size,
237                       block_device_ioctl handler,
238                       char *name)
239{
240    int bs_log2;
241    int i;
242    disk_device *dd;
243    rtems_status_code rc;
244    rtems_bdpool_id pool;
245    rtems_device_major_number major;
246    rtems_device_minor_number minor;
247
248    rtems_filesystem_split_dev_t (dev, major, minor);
249
250   
251    for (bs_log2 = 0, i = block_size; (i & 1) == 0; i >>= 1, bs_log2++);
252    if ((bs_log2 < 9) || (i != 1)) /* block size < 512 or not power of 2 */
253        return RTEMS_INVALID_NUMBER;
254   
255    rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
256    if (rc != RTEMS_SUCCESSFUL)
257        return rc;
258    diskdevs_protected = TRUE;
259
260    rc = rtems_bdbuf_find_pool(block_size, &pool);
261    if (rc != RTEMS_SUCCESSFUL)
262    {
263        diskdevs_protected = FALSE;
264        rtems_semaphore_release(diskdevs_mutex);
265        return rc;
266    }
267   
268    rc = create_disk(dev, name, &dd);
269    if (rc != RTEMS_SUCCESSFUL)
270    {
271        diskdevs_protected = FALSE;
272        rtems_semaphore_release(diskdevs_mutex);
273        return rc;
274    }
275   
276    dd->phys_dev = dd;
277    dd->uses = 0;
278    dd->start = 0;
279    dd->size = disk_size;
280    dd->block_size = block_size;
281    dd->block_size_log2 = bs_log2;
282    dd->ioctl = handler;
283    dd->pool = pool;
284
285    rc = rtems_io_register_name(name, major, minor);
286   
287    diskdevs_protected = FALSE;
288    rtems_semaphore_release(diskdevs_mutex);
289
290    return rc;
291}
292
293/* rtems_disk_create_log --
294 *     Create logical disk entry. Logical disk is contiguous area on physical
295 *     disk. Disk may be splitted to several logical disks in several ways:
296 *     manually or using information stored in blocks on physical disk
297 *     (DOS-like partition table, BSD disk label, etc). This function usually
298 *     invoked from application when application-specific splitting are in use,
299 *     or from generic code which handle different logical disk organizations.
300 *     This primitive will register device in rtems (invoke
301 *     rtems_io_register_name).
302 *
303 * PARAMETERS:
304 *     dev   - logical device identifier (major, minor numbers)
305 *     phys  - physical device (block device which holds this logical disk)
306 *             identifier
307 *     start - starting block number on the physical device
308 *     size  - logical disk size in blocks
309 *     name  - logical disk name
310 *
311 * RETURNS:
312 *     RTEMS_SUCCESSFUL if logical device successfully added, or error code
313 *     if error occured (device already registered, no physical device
314 *     exists, logical disk is out of physical disk boundaries, no memory
315 *     available).
316 */
317rtems_status_code
318rtems_disk_create_log(dev_t dev, dev_t phys, int start, int size, char *name)
319{
320    disk_device *dd;
321    disk_device *pdd;
322    rtems_status_code rc;
323    rtems_device_major_number major;
324    rtems_device_minor_number minor;
325
326    rtems_filesystem_split_dev_t (dev, major, minor);
327
328    rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
329    if (rc != RTEMS_SUCCESSFUL)
330        return rc;
331    diskdevs_protected = TRUE;
332
333    pdd = get_disk_entry(phys);
334    if (pdd == NULL)
335    {
336        diskdevs_protected = FALSE;
337        rtems_semaphore_release(diskdevs_mutex);
338        return RTEMS_INVALID_NUMBER;
339    }
340   
341    rc = create_disk(dev, name, &dd);
342    if (rc != RTEMS_SUCCESSFUL)
343    {
344        diskdevs_protected = FALSE;
345        rtems_semaphore_release(diskdevs_mutex);
346        return rc;
347    }
348   
349    dd->phys_dev = pdd;
350    dd->uses = 0;
351    dd->start = start;
352    dd->size = size;
353    dd->block_size = pdd->block_size;
354    dd->block_size_log2 = pdd->block_size_log2;
355    dd->ioctl = pdd->ioctl;
356
357    rc = rtems_io_register_name(name, major, minor);
358
359    diskdevs_protected = FALSE;
360    rc = rtems_semaphore_release(diskdevs_mutex);
361   
362    return rc;
363}
364
365/* rtems_disk_delete --
366 *     Delete physical or logical disk device. Device may be deleted if its
367 *     use counter (and use counters of all logical devices - if it is
368 *     physical device) equal to 0. When physical device deleted,
369 *     all logical devices deleted inherently. Appropriate devices removed
370 *     from "/dev" filesystem.
371 *
372 * PARAMETERS:
373 *     dev - device identifier (major, minor numbers)
374 *
375 * RETURNS:
376 *     RTEMS_SUCCESSFUL if block device successfully deleted, or error code
377 *     if error occured (device is not defined, device is in use).
378 */
379rtems_status_code
380rtems_disk_delete(dev_t dev)
381{
382    rtems_status_code rc;
383    int used;
384    rtems_device_major_number maj;
385    rtems_device_minor_number min;
386   
387    rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
388    if (rc != RTEMS_SUCCESSFUL)
389        return rc;
390    diskdevs_protected = TRUE;
391
392    /* Check if this device is in use -- calculate usage counter */
393    used = 0;
394    for (maj = 0; maj < disktab_size; maj++)
395    {
396        struct disk_device_table *dtab = disktab + maj;
397        if (dtab != NULL)
398        {
399            for (min = 0; min < dtab->size; min++)
400            {
401                disk_device *dd = dtab->minor[min];
402                if ((dd != NULL) && (dd->phys_dev->dev == dev))
403                    used += dd->uses;
404            }
405        }
406    }
407   
408    if (used != 0)
409    {
410        diskdevs_protected = FALSE;
411        rtems_semaphore_release(diskdevs_mutex);
412        return RTEMS_RESOURCE_IN_USE;
413    }
414
415    /* Delete this device and all of its logical devices */
416    for (maj = 0; maj < disktab_size; maj++)
417    {
418        struct disk_device_table *dtab = disktab +maj;
419        if (dtab != NULL)
420        {
421            for (min = 0; min < dtab->size; min++)
422            {
423                disk_device *dd = dtab->minor[min];
424                if ((dd != NULL) && (dd->phys_dev->dev == dev))
425                {
426                    unlink(dd->name);
427                    free(dd->name);
428                    free(dd);
429                    dtab->minor[min] = NULL;
430                }
431            }
432        }
433    }
434   
435    diskdevs_protected = FALSE;
436    rc = rtems_semaphore_release(diskdevs_mutex);
437    return rc;
438}
439
440/* rtems_disk_lookup --
441 *     Find block device descriptor by its device identifier.
442 *
443 * PARAMETERS:
444 *     dev - device identifier (major, minor numbers)
445 *
446 * RETURNS:
447 *     pointer to the block device descriptor, or NULL if no such device
448 *     exists.
449 */
450disk_device *
451rtems_disk_lookup(dev_t dev)
452{
453    rtems_interrupt_level level;
454    disk_device *dd;
455    rtems_status_code rc;
456   
457    rtems_interrupt_disable(level);
458    if (diskdevs_protected)
459    {
460        rtems_interrupt_enable(level);
461        rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, 
462                                    RTEMS_NO_TIMEOUT);
463        if (rc != RTEMS_SUCCESSFUL)
464            return NULL;
465        diskdevs_protected = TRUE;
466        dd = get_disk_entry(dev);
467        dd->uses++;
468        diskdevs_protected = FALSE;
469        rtems_semaphore_release(diskdevs_mutex);
470        return dd;
471    }
472    else
473    {
474        /* Frequent and quickest case */
475        dd = get_disk_entry(dev);
476        dd->uses++;
477        rtems_interrupt_enable(level);
478        return dd;
479    }
480}
481
482/* rtems_disk_release --
483 *     Release disk_device structure (decrement usage counter to 1).
484 *
485 * PARAMETERS:
486 *     dd - pointer to disk device structure
487 *
488 * RETURNS:
489 *     RTEMS_SUCCESSFUL
490 */
491rtems_status_code
492rtems_disk_release(disk_device *dd)
493{
494    rtems_interrupt_level level;
495    rtems_interrupt_disable(level);
496    dd->uses--;
497    rtems_interrupt_enable(level);
498    return RTEMS_SUCCESSFUL;
499}
500
501/* rtems_disk_next --
502 *     Disk device enumerator. Looking for device having device number larger
503 *     than dev and return disk device descriptor for it. If there are no
504 *     such device, NULL value returned.
505 *
506 * PARAMETERS:
507 *     dev - device number (use -1 to start search)
508 *
509 * RETURNS:
510 *     Pointer to the disk descriptor for next disk device, or NULL if all
511 *     devices enumerated.
512 */
513disk_device *
514rtems_disk_next(dev_t dev)
515{
516    rtems_device_major_number major;
517    rtems_device_minor_number minor;
518    struct disk_device_table *dtab;
519
520    dev++;
521    rtems_filesystem_split_dev_t (dev, major, minor);
522
523    if (major >= disktab_size)
524        return NULL;
525   
526    dtab = disktab + major;
527    while (TRUE) 
528    {
529        if ((dtab == NULL) || (minor > dtab->size))
530        {
531             major++; minor = 0;
532             if (major >= disktab_size)
533                 return NULL;
534             dtab = disktab + major;
535        }
536        else if (dtab->minor[minor] == NULL)
537        {
538            minor++;
539        }
540        else
541            return dtab->minor[minor];
542    }
543}
544
545/* rtems_disk_initialize --
546 *     Initialization of disk device library (initialize all data structures,
547 *     etc.)
548 *
549 * PARAMETERS:
550 *     none
551 *
552 * RETURNS:
553 *     RTEMS_SUCCESSFUL if library initialized, or error code if error
554 *     occured.
555 */
556rtems_status_code
557rtems_disk_io_initialize(void)
558{
559    rtems_status_code rc;
560
561    if (disk_io_initialized)
562        return RTEMS_SUCCESSFUL;
563   
564    disktab_size = DISKTAB_INITIAL_SIZE;
565    disktab = calloc(disktab_size, sizeof(struct disk_device_table));
566    if (disktab == NULL)
567        return RTEMS_NO_MEMORY;
568
569    diskdevs_protected = FALSE;
570    rc = rtems_semaphore_create(
571        rtems_build_name('D', 'D', 'E', 'V'), 1,
572        RTEMS_FIFO | RTEMS_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | 
573        RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0, &diskdevs_mutex);
574   
575    if (rc != RTEMS_SUCCESSFUL)
576    {
577        free(disktab);
578        return rc;
579    }
580   
581    rc = rtems_bdbuf_init(rtems_bdbuf_configuration,
582                          rtems_bdbuf_configuration_size);
583   
584    if (rc != RTEMS_SUCCESSFUL)
585    {
586        rtems_semaphore_delete(diskdevs_mutex);
587        free(disktab);
588        return rc;
589    }
590   
591    disk_io_initialized = 1;
592    return RTEMS_SUCCESSFUL;
593}
594
595/* rtems_disk_io_done --
596 *     Release all resources allocated for disk device interface.
597 *
598 * PARAMETERS:
599 *     none
600 *
601 * RETURNS:
602 *     RTEMS_SUCCESSFUL if all resources released, or error code if error
603 *     occured.
604 */
605rtems_status_code
606rtems_disk_io_done(void)
607{
608    rtems_device_major_number maj;
609    rtems_device_minor_number min;
610    rtems_status_code rc;
611
612    /* Free data structures */   
613    for (maj = 0; maj < disktab_size; maj++)
614    {
615        struct disk_device_table *dtab = disktab + maj;
616        if (dtab != NULL)
617        {
618            for (min = 0; min < dtab->size; min++)
619            {
620                disk_device *dd = dtab->minor[min];
621                unlink(dd->name);
622                free(dd->name);
623                free(dd);
624            }
625            free(dtab);
626        }
627    }
628    free(disktab);
629
630    rc = rtems_semaphore_release(diskdevs_mutex);
631   
632    /* XXX bdbuf should be released too! */
633    disk_io_initialized = 0;
634    return rc;
635}
Note: See TracBrowser for help on using the repository browser.