OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [cpukit/] [libblock/] [src/] [diskdevs.c] - Blame information for rev 1026

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.