source: rtems/cpukit/libblock/src/nvdisk.c @ 2eb89ad

4.104.114.9
Last change on this file since 2eb89ad was 2eb89ad, checked in by Chris Johns <chrisj@…>, on Aug 2, 2008 at 6:23:45 AM

2008-08-02 Chris Johns (chrisj@…>

  • libblock/include/rtems/blkdev.h: Remove count and start from rtems_blkdev_request. Add RTEMS_BLKDEV_START_BLOCK macro.
  • libblock/src/bdbuf.c: Add read ahead blocks always consecutive comment. Change count to bufnum and remove start references. Sort the transfer list so blocks are consecutive where possible.
  • libblock/src/blkdev.c, libblock/src/nvdisk.c, libblock/src/ramdisk.c: Change count to bufnum and remove start references.
  • Property mode set to 100644
File size: 22.2 KB
Line 
1/*
2 * nvdisk.c -- Non-volatile disk block device implementation
3 *
4 * Copyright (C) 2007 Chris Johns
5 *
6 * The license and distribution terms for this file may be
7 * found in the file LICENSE in this distribution or at
8 * http://www.rtems.com/license/LICENSE.
9 *
10 * $Id$
11 */
12
13#if HAVE_CONFIG_H
14#include "config.h"
15#endif
16
17#include <rtems.h>
18#include <rtems/libio.h>
19#include <errno.h>
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <inttypes.h>
24
25#include "rtems/blkdev.h"
26#include "rtems/diskdevs.h"
27#include "rtems/nvdisk.h"
28
29/**
30 * @note
31 *
32 * The use of pages can vary. The rtems_nvdisk_*_page set
33 * routines use an absolute page number relative to the segment
34 * while all other page numbera are relative to the number of
35 * page descriptor pages a segment has. You need to add the
36 * number of page descriptor pages (pages_desc) to the page number
37 * when call the rtems_nvdisk_*_page functions.
38 *
39 * You must always show the page number as relative in any trace
40 * or error message as device-page and if you have to
41 * the page number as absolute use device~page. This
42 * can be seen in the page copy routine.
43 *
44 * The code is like this to avoid needing the pass the pages_desc
45 * value around. It is only used in selected places and so the
46 * extra parameter was avoided.
47 */
48
49/**
50 * Control tracing. It can be compiled out of the code for small
51 * footprint targets. Leave in by default.
52 */
53#if !defined (RTEMS_NVDISK_TRACE)
54#define RTEMS_NVDISK_TRACE 0
55#endif
56
57/**
58 * Provide a basic boolean type.
59 */
60#define bool  int
61#define true  (1)
62#define false (0)
63
64/**
65 * NV Device Control holds the segment controls
66 */
67typedef struct rtems_nvdisk_device_ctl
68{
69  /**
70   * The device this segment resides on.
71   */
72  uint32_t device;
73 
74  /**
75   * Total number of pages in the device.
76   */
77  uint32_t pages;
78
79  /**
80   * Number of pages used for page checksums.
81   */
82  uint32_t pages_desc;
83
84  /**
85   * First block number for this device.
86   */
87  uint32_t block_base;
88
89  /**
90   * Device descriptor.
91   */
92  const rtems_nvdisk_device_desc* descriptor;
93} rtems_nvdisk_device_ctl;
94
95/**
96 * The NV disk control structure for a single disk. There is one
97 * for each minor disk in the system.
98 */
99typedef struct rtems_mvdisk
100{
101  rtems_device_major_number major;        /**< The driver's major number. */
102  rtems_device_minor_number minor;        /**< The driver's minor number. */
103  uint32_t                  flags;        /**< configuration flags. */
104  uint32_t                  block_size;   /**< The block size for this disk. */
105  uint32_t                  block_count;  /**< The number of available blocks. */
106  rtems_nvdisk_device_ctl*  devices;      /**< The NV devices for this disk. */
107  uint32_t                  device_count; /**< The number of NV devices. */
108  uint32_t                  cs_pages;     /**< The num of pages of checksums. */
109  rtems_id                  lock;         /**< Mutex for threading protection.*/
110  uint32_t info_level;                    /**< The info trace level. */
111} rtems_nvdisk;
112
113/**
114 * The array of NV disks we support.
115 */
116static rtems_nvdisk* rtems_nvdisks;
117
118/**
119 * The number of NV disks we have.
120 */
121static uint32_t rtems_nvdisk_count;
122
123/**
124 * The CRC16 factor table. Created during initialisation.
125 */
126static uint16_t* rtems_nvdisk_crc16_factor;
127
128/**
129 * Calculate the CRC16 checksum.
130 *
131 * @param _b The byte to checksum.
132 * @param _c The current checksum.
133 */
134#define rtems_nvdisk_calc_crc16(_b, _c) \
135  rtems_nvdisk_crc16_factor[((_b) ^ ((_c) & 0xff)) & 0xff] ^ (((_c) >> 8) & 0xff)
136
137/**
138 * Generate the CRC table.
139 *
140 * @param pattern The seed pattern for the table of factors.
141 * @relval RTEMS_SUCCESSFUL The table was generated.
142 * @retval RTEMS_NO_MEMORY The table could not be allocated from the heap.
143 */
144rtems_status_code
145rtems_nvdisk_crc16_gen_factors (uint16_t pattern)
146{
147  uint32_t b;
148
149  rtems_nvdisk_crc16_factor = malloc (sizeof (uint16_t) * 256);
150  if (!rtems_nvdisk_crc16_factor)
151    return RTEMS_NO_MEMORY;
152
153  for (b = 0; b < 256; b++)
154  {
155    uint32_t i;
156    uint16_t v = b;
157    for (i = 8; i--;)
158      v = v & 1 ? (v >> 1) ^ pattern : v >> 1;
159    rtems_nvdisk_crc16_factor[b] = v & 0xffff;
160  }
161  return RTEMS_SUCCESSFUL;
162}
163
164#if RTEMS_NVDISK_TRACE
165/**
166 * Print a message to the nvdisk output and flush it.
167 *
168 * @param nvd The nvdisk control structure.
169 * @param format The format string. See printf for details.
170 * @param ... The arguments for the format text.
171 * @return int The number of bytes written to the output.
172 */
173static int
174rtems_nvdisk_printf (const rtems_nvdisk* nvd, const char *format, ...)
175{
176  int ret = 0;
177  if (nvd->info_level >= 3)
178  {
179    va_list args;
180    va_start (args, format);
181    fprintf (stdout, "nvdisk:");
182    ret =  vfprintf (stdout, format, args);
183    fprintf (stdout, "\n");
184    fflush (stdout);
185  }
186  return ret;
187}
188
189/**
190 * Print a info message to the nvdisk output and flush it.
191 *
192 * @param nvd The nvdisk control structure.
193 * @param format The format string. See printf for details.
194 * @param ... The arguments for the format text.
195 * @return int The number of bytes written to the output.
196 */
197static int
198rtems_nvdisk_info (const rtems_nvdisk* nvd, const char *format, ...)
199{
200  int ret = 0;
201  if (nvd->info_level >= 2)
202  {
203    va_list args;
204    va_start (args, format);
205    fprintf (stdout, "nvdisk:");
206    ret =  vfprintf (stdout, format, args);
207    fprintf (stdout, "\n");
208    fflush (stdout);
209  }
210  return ret;
211}
212
213/**
214 * Print a warning to the nvdisk output and flush it.
215 *
216 * @param nvd The nvdisk control structure.
217 * @param format The format string. See printf for details.
218 * @param ... The arguments for the format text.
219 * @return int The number of bytes written to the output.
220 */
221static int
222rtems_nvdisk_warning (const rtems_nvdisk* nvd, const char *format, ...)
223{
224  int ret = 0;
225  if (nvd->info_level >= 1)
226  {
227    va_list args;
228    va_start (args, format);
229    fprintf (stdout, "nvdisk:warning:");
230    ret =  vfprintf (stdout, format, args);
231    fprintf (stdout, "\n");
232    fflush (stdout);
233  }
234  return ret;
235}
236#endif
237
238/**
239 * Print an error to the nvdisk output and flush it.
240 *
241 * @param format The format string. See printf for details.
242 * @param ... The arguments for the format text.
243 * @return int The number of bytes written to the output.
244 */
245static int
246rtems_nvdisk_error (const char *format, ...)
247{
248  int ret;
249  va_list args;
250  va_start (args, format);
251  fprintf (stderr, "nvdisk:error:");
252  ret =  vfprintf (stderr, format, args);
253  fprintf (stderr, "\n");
254  fflush (stderr);
255  return ret;
256}
257
258/**
259 * Get the descriptor for a device.
260 */
261static const rtems_nvdisk_device_desc*
262rtems_nvdisk_device_descriptor (const rtems_nvdisk* nvd, uint32_t device)
263{
264  return nvd->devices[device].descriptor;
265}
266
267/**
268 * Read a block of data from a device.
269 */
270static int
271rtems_nvdisk_device_read (const rtems_nvdisk* nvd,
272                          uint32_t            device,
273                          uint32_t            offset,
274                          void*               buffer,
275                          uint32_t            size)
276{
277  const rtems_nvdisk_device_desc*     dd;
278  const rtems_nvdisk_driver_handlers* ops;
279  dd  = rtems_nvdisk_device_descriptor (nvd, device);
280  ops = nvd->devices[device].descriptor->nv_ops;
281#if RTEMS_NVDISK_TRACE
282  rtems_nvdisk_printf (nvd, "  dev-read: %02d-%08x: s=%d",
283                      device, offset, size);
284#endif
285  return ops->read (device, dd->flags, dd->base, offset, buffer, size); 
286}
287
288/**
289 * Write a block of data to a device.
290 */
291static int
292rtems_nvdisk_device_write (const rtems_nvdisk* nvd,
293                           uint32_t            device,
294                           uint32_t            offset,
295                           const void*         buffer,
296                           uint32_t            size)
297{
298  const rtems_nvdisk_device_desc*     dd;
299  const rtems_nvdisk_driver_handlers* ops;
300  dd  = rtems_nvdisk_device_descriptor (nvd, device);
301  ops = nvd->devices[device].descriptor->nv_ops;
302#if RTEMS_NVDISK_TRACE
303  rtems_nvdisk_printf (nvd, "  dev-write: %02d-%08x: s=%d",
304                      device, offset, size);
305#endif
306  return ops->write (device, dd->flags, dd->base, offset, buffer, size); 
307}
308
309#if NOT_USED
310/**
311 * Verify the data with the data in a segment.
312 */
313static int
314rtems_nvdisk_device_verify (const rtems_nvdisk* nvd,
315                            uint32_t            device,
316                            uint32_t            offset,
317                            const void*         buffer,
318                            uint32_t            size)
319{
320  const rtems_nvdisk_device_desc*     dd;
321  const rtems_nvdisk_driver_handlers* ops;
322  dd  = rtems_nvdisk_device_descriptor (nvd, device);
323  ops = nvd->devices[device].descriptor->nv_ops;
324#if RTEMS_NVDISK_TRACE
325  rtems_nvdisk_printf (nvd, "  seg-verify: %02d-%08x: s=%d",
326                      device, offset, size);
327#endif
328  return ops->verify (device, dd->flags, dd->base, offset, buffer, size); 
329}
330#endif
331
332/**
333 * Read a page of data from the device.
334 */
335static int
336rtems_nvdisk_read_page (const rtems_nvdisk* nvd,
337                        uint32_t            device,
338                        uint32_t            page,
339                        void*               buffer)
340{
341  return rtems_nvdisk_device_read (nvd, device,
342                                   page * nvd->block_size, buffer,
343                                   nvd->block_size);
344}
345
346/**
347 * Write a page of data to a device.
348 */
349static int
350rtems_nvdisk_write_page (const rtems_nvdisk* nvd,
351                         uint32_t            device,
352                         uint32_t            page,
353                         const void*         buffer)
354{
355  return rtems_nvdisk_device_write (nvd, device,
356                                    page * nvd->block_size,
357                                    buffer, nvd->block_size);
358}
359
360/**
361 * Read the checksum from the device.
362 */
363static int
364rtems_nvdisk_read_checksum (const rtems_nvdisk* nvd,
365                            uint32_t            device,
366                            uint32_t            page,
367                            uint16_t*           cs)
368{
369  return rtems_nvdisk_device_read (nvd, device,
370                                   page * sizeof (uint16_t),
371                                   cs, sizeof (uint16_t));
372}
373
374/**
375 * Write the checksum to the device.
376 */
377static int
378rtems_nvdisk_write_checksum (const rtems_nvdisk* nvd,
379                             uint32_t            device,
380                             uint32_t            page,
381                             const uint16_t      cs)
382{
383  return rtems_nvdisk_device_write (nvd, device,
384                                    page * sizeof (uint16_t),
385                                    &cs, sizeof (uint16_t));
386}
387
388/**
389 * Calculate the pages in a device give the device descriptor and the
390 * page size.
391 *
392 * @param dd The device descriptor.
393 * @param page_size The page size in bytes.
394 */
395static uint32_t
396rtems_nvdisk_pages_in_device (const rtems_nvdisk*             nvd,
397                              const rtems_nvdisk_device_desc* dd)
398{
399  return dd->size / nvd->block_size;
400}
401
402/**
403 * Calculate the number of pages needed to hold the page descriptors.
404 * The calculation need to round up.
405 */
406static uint32_t
407rtems_nvdisk_page_desc_pages (const rtems_nvdisk*             nvd,
408                              const rtems_nvdisk_device_desc* dd)
409{
410  uint32_t pages = rtems_nvdisk_pages_in_device (nvd, dd);
411  uint32_t bytes = pages * sizeof (uint16_t);
412  return ((bytes - 1) / nvd->block_size) + 1;
413}
414
415/**
416 * Calculate the checksum of a page.
417 */
418static uint16_t
419rtems_nvdisk_page_checksum (const uint8_t* buffer, uint32_t page_size)
420{
421  uint16_t cs = 0xffff;
422  uint32_t i;
423
424  for (i = 0; i < page_size; i++, buffer++)
425    cs = rtems_nvdisk_calc_crc16 (cs, *buffer);
426
427  return cs;
428}
429
430/**
431 * Map a block to a device.
432 */
433static rtems_nvdisk_device_ctl*
434rtems_nvdisk_get_device (rtems_nvdisk* nvd, uint32_t block)
435{
436  uint32_t device;
437 
438  if (block >= nvd->block_count)
439  {
440    rtems_nvdisk_error ("read-block: bad block: %d", block);
441    return NULL;
442  }
443
444  for (device = 0; device < nvd->device_count; device++)
445  {
446    rtems_nvdisk_device_ctl* dc = &nvd->devices[device];
447    if ((block >= dc->block_base) &&
448        (block < (dc->block_base + dc->pages - dc->pages_desc)))
449      return dc;
450  }
451
452  rtems_nvdisk_error ("map-block:%d: no device/page map found", block);
453
454  return NULL;
455}
456
457/**
458 * Get the page for a block in a device.
459 */
460static uint32_t
461rtems_nvdisk_get_page (rtems_nvdisk_device_ctl* dc,
462                       uint32_t                 block)
463{
464  return block - dc->block_base;
465}
466   
467/**
468 * Read a block. The block is checked to see if the page referenced
469 * is valid and the page has a valid crc.
470 *
471 * @param nvd The rtems_nvdisk control table.
472 * @param block The block number to read.
473 * @param buffer The buffer to write the data into.
474 * @return 0 No error.
475 * @return EIO Invalid block number or crc.
476 */
477static int
478rtems_nvdisk_read_block (rtems_nvdisk* nvd, uint32_t block, uint8_t* buffer)
479{
480  rtems_nvdisk_device_ctl* dc;
481  uint32_t                 page;
482  uint16_t                 crc;
483  uint16_t                 cs;
484  int                      ret;
485 
486  dc = rtems_nvdisk_get_device (nvd, block);
487
488  if (!dc)
489    return EIO;
490
491  page = rtems_nvdisk_get_page (dc, block);
492 
493#if RTEMS_NVDISK_TRACE
494  rtems_nvdisk_info (nvd, " read-block:%d=>%02d-%03d, cs:%04x",
495                     block, dc->device, page, crc);
496#endif
497
498  ret = rtems_nvdisk_read_checksum (nvd, dc->device, page, &crc);
499
500  if (ret)
501    return ret;
502
503  if (crc == 0xffff)
504  {
505#if RTEMS_NVDISK_TRACE
506    rtems_nvdisk_warning (nvd, "read-block: crc not set: %d", block);
507#endif
508    memset (buffer, 0, nvd->block_size);
509    return 0;
510  }
511 
512  ret = rtems_nvdisk_read_page (nvd, dc->device, page + dc->pages_desc, buffer);
513
514  if (ret)
515    return ret;
516
517  cs = rtems_nvdisk_page_checksum (buffer, nvd->block_size);
518 
519  if (cs != crc)
520  {   
521    rtems_nvdisk_error ("read-block: crc failure: %d: buffer:%04x page:%04x",
522                        block, cs, crc);
523    return EIO;
524  }
525
526  return 0;
527}
528
529/**
530 * Write a block.
531 *
532 * @param nvd The rtems_nvdisk control table.
533 * @param block The block number to read.
534 * @param block_size The size of the block. Must match what we have.
535 * @param buffer The buffer to write the data into.
536 * @return 0 No error.
537 * @return EIO Invalid block size, block number, segment pointer, crc,
538 *             page flags.
539 */
540static int
541rtems_nvdisk_write_block (rtems_nvdisk*        nvd,
542                          uint32_t             block,
543                          const unsigned char* buffer)
544{
545  rtems_nvdisk_device_ctl* dc;
546  uint32_t                 page;
547  uint16_t                 cs;
548  int                      ret;
549 
550  dc = rtems_nvdisk_get_device (nvd, block);
551
552  if (!dc)
553    return EIO;
554
555  page = rtems_nvdisk_get_page (dc, block);
556 
557  cs = rtems_nvdisk_page_checksum (buffer, nvd->block_size);
558
559#if RTEMS_NVDISK_TRACE
560  rtems_nvdisk_info (nvd, " write-block:%d=>%02d-%03d", block, dc->device, page);
561#endif
562
563  ret = rtems_nvdisk_write_page (nvd, dc->device, page + dc->pages_desc, buffer);
564
565  if (ret)
566    return ret;
567
568  return rtems_nvdisk_write_checksum (nvd, dc->device, page, cs);
569}
570
571/**
572 * Disk READ request handler. This primitive copies data from the
573 * flash disk to the supplied buffer and invoke the callout function
574 * to inform upper layer that reading is completed.
575 *
576 * @param req Pointer to the READ block device request info.
577 * @retval int The ioctl return value.
578 */
579static int
580rtems_nvdisk_read (rtems_nvdisk* nvd, rtems_blkdev_request* req)
581{
582  rtems_blkdev_sg_buffer* sg = req->bufs;
583  uint32_t                b;
584  int32_t                 remains;
585  int                     ret = 0;
586
587#if RTEMS_NVDISK_TRACE
588  rtems_nvdisk_info (nvd, "read: blocks=%d", req->bufnum);
589#endif
590
591  remains = req->bufnum * nvd->block_size;
592 
593  for (b = 0; b < req->bufnum; b++, sg++)
594  {
595    uint32_t length = sg->length;
596
597    if (remains <= 0)
598      rtems_nvdisk_error ("nvdisk-read: remains size <= 0");
599     
600    if (sg->length != nvd->block_size)
601    {
602      rtems_nvdisk_error ("nvdisk-read: length is not the block size: "\
603                         "bd:%d nvd:%d", sg->length, nvd->block_size);
604
605      if (length > nvd->block_size)
606        length = nvd->block_size;
607    }
608
609    ret = rtems_nvdisk_read_block (nvd, sg->block, sg->buffer);
610
611    if (ret)
612      break;
613
614    remains -= length;
615  }
616
617  req->req_done (req->done_arg,
618                 ret ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR, ret);
619 
620  return ret;
621}
622
623/**
624 * Flash disk WRITE request handler. This primitive copies data from
625 * supplied buffer to NV disk and invoke the callout function to inform
626 * upper layer that writing is completed.
627 *
628 * @param req Pointers to the WRITE block device request info.
629 * @retval int The ioctl return value.
630 */
631static int
632rtems_nvdisk_write (rtems_nvdisk* nvd, rtems_blkdev_request* req)
633{
634  rtems_blkdev_sg_buffer* sg = req->bufs;
635  uint32_t                b;
636  int                     ret = 0;
637
638#if RTEMS_NVDISK_TRACE
639  rtems_nvdisk_info (nvd, "write: blocks=%d", req->bufnum);
640#endif
641
642  for (b = 0; b < req->bufnum; b++, sg++)
643  {
644    if (sg->length != nvd->block_size)
645    {
646      rtems_nvdisk_error ("nvdisk-write: length is not the block size: " \
647                         "bd:%d nvd:%d", sg->length, nvd->block_size);
648    }
649
650    ret = rtems_nvdisk_write_block (nvd, sg->block, sg->buffer);
651
652    if (ret)
653      break;
654  }
655
656  req->req_done (req->done_arg,
657                 ret ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR, ret);
658 
659  return 0;
660}
661
662/**
663 * NV disk erase disk sets all the checksums for 0xffff.
664 *
665 * @param nvd The nvdisk data.
666 * @retval int The ioctl return value.
667 */
668static int
669rtems_nvdisk_erase_disk (rtems_nvdisk* nvd)
670{
671  uint32_t device;
672
673#if RTEMS_NVDISK_TRACE
674  rtems_nvdisk_info (nvd, "erase-disk");
675#endif
676
677  for (device = 0; device < nvd->device_count; device++)
678  {
679    rtems_nvdisk_device_ctl* dc = &nvd->devices[device];
680    uint32_t                 page;
681    for (page = 0; page < (dc->pages - dc->pages_desc); page++)
682    {
683      int ret = rtems_nvdisk_write_checksum (nvd, dc->device, page, 0xffff);
684      if (ret)
685        return ret;
686    }
687  }
688
689  return 0;
690}
691
692/**
693 * NV disk IOCTL handler.
694 *
695 * @param dev Device number (major, minor number).
696 * @param req IOCTL request code.
697 * @param argp IOCTL argument.
698 * @retval The IOCTL return value
699 */
700static int
701rtems_nvdisk_ioctl (dev_t dev, uint32_t req, void* argp)
702{
703  rtems_device_minor_number minor = rtems_filesystem_dev_minor_t (dev);
704  rtems_blkdev_request*     r = argp;
705  rtems_status_code         sc;
706
707  if (minor >= rtems_nvdisk_count)
708  {
709    errno = ENODEV;
710    return -1;
711  }
712       
713  if (rtems_nvdisks[minor].device_count == 0)
714  {
715    errno = ENODEV;
716    return -1;
717  }
718       
719  errno = 0;
720
721  sc = rtems_semaphore_obtain (rtems_nvdisks[minor].lock, RTEMS_WAIT, 0);
722  if (sc != RTEMS_SUCCESSFUL)
723    errno = EIO;
724  else
725  {
726    switch (req)
727    {
728      case RTEMS_BLKIO_REQUEST:
729        switch (r->req)
730        {
731          case RTEMS_BLKDEV_REQ_READ:
732            errno = rtems_nvdisk_read (&rtems_nvdisks[minor], r);
733            break;
734           
735          case RTEMS_BLKDEV_REQ_WRITE:
736            errno = rtems_nvdisk_write (&rtems_nvdisks[minor], r);
737            break;
738           
739          default:
740            errno = EBADRQC;
741            break;
742        }
743        break;
744
745      case RTEMS_NVDISK_IOCTL_ERASE_DISK:
746        errno = rtems_nvdisk_erase_disk (&rtems_nvdisks[minor]);
747        break;
748       
749      case RTEMS_NVDISK_IOCTL_INFO_LEVEL:
750        rtems_nvdisks[minor].info_level = (uint32_t) argp;
751        break;
752       
753      default:
754        errno = EBADRQC;
755        break;
756    }
757
758    sc = rtems_semaphore_release (rtems_nvdisks[minor].lock);
759    if (sc != RTEMS_SUCCESSFUL)
760      errno = EIO;
761  }
762
763  return errno == 0 ? 0 : -1;
764}
765
766/**
767 * NV disk device driver initialization.
768 *
769 * @todo Memory clean up on error is really badly handled.
770 *
771 * @param major NV disk major device number.
772 * @param minor Minor device number, not applicable.
773 * @param arg Initialization argument, not applicable.
774 */
775rtems_device_driver
776rtems_nvdisk_initialize (rtems_device_major_number major,
777                        rtems_device_minor_number minor,
778                        void*                     arg)
779{
780  const rtems_nvdisk_config* c = rtems_nvdisk_configuration;
781  rtems_nvdisk*              nvd;
782  rtems_status_code          sc;
783
784  sc = rtems_disk_io_initialize ();
785  if (sc != RTEMS_SUCCESSFUL)
786    return sc;
787
788  sc = rtems_nvdisk_crc16_gen_factors (0x8408);
789  if (sc != RTEMS_SUCCESSFUL)
790      return sc;
791
792  rtems_nvdisks = calloc (rtems_nvdisk_configuration_size,
793                          sizeof (rtems_nvdisk));
794
795  if (!rtems_nvdisks)
796    return RTEMS_NO_MEMORY;
797
798  for (minor = 0; minor < rtems_nvdisk_configuration_size; minor++, c++)
799  {
800    char     name[sizeof (RTEMS_NVDISK_DEVICE_BASE_NAME) + 10];
801    dev_t    dev = rtems_filesystem_make_dev_t (major, minor);
802    uint32_t device;
803    uint32_t blocks = 0;
804
805    nvd = &rtems_nvdisks[minor];
806 
807    snprintf (name, sizeof (name),
808              RTEMS_NVDISK_DEVICE_BASE_NAME "%" PRIu32, minor);
809 
810    nvd->major        = major;
811    nvd->minor        = minor;
812    nvd->flags        = c->flags;
813    nvd->block_size   = c->block_size;
814    nvd->info_level   = c->info_level;
815
816    nvd->devices = calloc (c->device_count, sizeof (rtems_nvdisk_device_ctl));
817    if (!nvd->devices)
818      return RTEMS_NO_MEMORY;
819
820    for (device = 0; device < c->device_count; device++)
821    {
822      rtems_nvdisk_device_ctl* dc = &nvd->devices[device];
823
824      dc->device     = device;
825      dc->pages      = rtems_nvdisk_pages_in_device (nvd, &c->devices[device]);
826      dc->pages_desc = rtems_nvdisk_page_desc_pages (nvd, &c->devices[device]);
827      dc->block_base = blocks;
828     
829      blocks += dc->pages - dc->pages_desc;
830
831      dc->descriptor = &c->devices[device];
832    }
833
834    nvd->block_count  = blocks;
835    nvd->device_count = c->device_count;
836
837    sc = rtems_disk_create_phys(dev, c->block_size, blocks,
838                                rtems_nvdisk_ioctl, name);
839    if (sc != RTEMS_SUCCESSFUL)
840    {
841      rtems_nvdisk_error ("disk create phy failed");
842      return sc;
843    }
844 
845    sc = rtems_semaphore_create (rtems_build_name ('N', 'V', 'D', 'K'), 1,
846                                 RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE |
847                                 RTEMS_INHERIT_PRIORITY, 0, &nvd->lock);
848    if (sc != RTEMS_SUCCESSFUL)
849    {
850      rtems_nvdisk_error ("disk lock create failed");
851      return sc;
852    }
853  }
854
855  rtems_nvdisk_count = rtems_nvdisk_configuration_size;
856
857  return RTEMS_SUCCESSFUL;
858}
Note: See TracBrowser for help on using the repository browser.