File indexing completed on 2025-05-11 08:24:14
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054 #ifdef HAVE_CONFIG_H
0055 #include "config.h"
0056 #endif
0057
0058 #include <rtems.h>
0059 #include <rtems/libio.h>
0060 #include <errno.h>
0061 #include <stdlib.h>
0062 #include <stdio.h>
0063 #include <string.h>
0064 #include <unistd.h>
0065 #include <inttypes.h>
0066
0067 #include <rtems/blkdev.h>
0068 #include <rtems/flashdisk.h>
0069 #include <rtems/thread.h>
0070
0071
0072
0073
0074
0075 #if !defined (RTEMS_FDISK_TRACE)
0076 #define RTEMS_FDISK_TRACE 1
0077 #endif
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088 typedef struct rtems_fdisk_page_desc
0089 {
0090 uint16_t crc;
0091 uint16_t flags;
0092 uint32_t block;
0093 } rtems_fdisk_page_desc;
0094
0095
0096
0097
0098 #define RTEMS_FDISK_PAGE_ACTIVE (1 << 0)
0099
0100
0101
0102
0103 #define RTEMS_FDISK_PAGE_USED (1 << 1)
0104
0105
0106
0107
0108
0109 typedef struct rtems_fdisk_segment_ctl
0110 {
0111
0112
0113
0114 struct rtems_fdisk_segment_ctl* next;
0115
0116
0117
0118
0119 const rtems_fdisk_segment_desc* descriptor;
0120
0121
0122
0123
0124 uint32_t device;
0125
0126
0127
0128
0129
0130 uint32_t segment;
0131
0132
0133
0134
0135
0136 rtems_fdisk_page_desc* page_descriptors;
0137
0138
0139
0140
0141
0142
0143 uint32_t pages;
0144 uint32_t pages_desc;
0145 uint32_t pages_active;
0146 uint32_t pages_used;
0147 uint32_t pages_bad;
0148
0149 uint32_t failed;
0150
0151 uint32_t erased;
0152
0153 } rtems_fdisk_segment_ctl;
0154
0155
0156
0157
0158 typedef struct rtems_fdisk_segment_ctl_queue
0159 {
0160 rtems_fdisk_segment_ctl* head;
0161 rtems_fdisk_segment_ctl* tail;
0162 uint32_t count;
0163 } rtems_fdisk_segment_ctl_queue;
0164
0165
0166
0167
0168 typedef struct rtems_fdisk_device_ctl
0169 {
0170 rtems_fdisk_segment_ctl* segments;
0171 uint32_t segment_count;
0172 const rtems_fdisk_device_desc* descriptor;
0173 } rtems_fdisk_device_ctl;
0174
0175
0176
0177
0178 typedef struct rtems_fdisk_block_ctl
0179 {
0180 rtems_fdisk_segment_ctl* segment;
0181 uint32_t page;
0182 } rtems_fdisk_block_ctl;
0183
0184
0185
0186
0187
0188 typedef struct rtems_flashdisk
0189 {
0190 rtems_device_major_number major;
0191 rtems_device_minor_number minor;
0192
0193 uint32_t flags;
0194
0195 uint32_t compact_segs;
0196 uint32_t avail_compact_segs;
0197
0198
0199 uint32_t block_size;
0200 rtems_fdisk_block_ctl* blocks;
0201
0202 uint32_t block_count;
0203 uint32_t unavail_blocks;
0204 uint32_t starvation_threshold;
0205 uint32_t erased_blocks;
0206
0207 rtems_fdisk_device_ctl* devices;
0208
0209 uint32_t device_count;
0210
0211 rtems_fdisk_segment_ctl_queue available;
0212
0213 rtems_fdisk_segment_ctl_queue used;
0214
0215 rtems_fdisk_segment_ctl_queue erase;
0216
0217 rtems_fdisk_segment_ctl_queue failed;
0218
0219 rtems_mutex lock;
0220
0221 uint8_t* copy_buffer;
0222
0223 uint32_t info_level;
0224
0225 uint32_t starvations;
0226 } rtems_flashdisk;
0227
0228
0229
0230
0231 static uint16_t* rtems_fdisk_crc16_factor;
0232
0233
0234
0235
0236
0237
0238
0239 #define rtems_fdisk_calc_crc16(_b, _c) \
0240 rtems_fdisk_crc16_factor[((_b) ^ ((_c) & 0xff)) & 0xff] ^ (((_c) >> 8) & 0xff)
0241
0242
0243
0244
0245
0246
0247
0248
0249 static rtems_status_code
0250 rtems_fdisk_crc16_gen_factors (uint16_t pattern)
0251 {
0252 uint32_t b;
0253
0254 rtems_fdisk_crc16_factor = malloc (sizeof (uint16_t) * 256);
0255 if (!rtems_fdisk_crc16_factor)
0256 return RTEMS_NO_MEMORY;
0257
0258 for (b = 0; b < 256; b++)
0259 {
0260 uint32_t i;
0261 uint16_t v = b;
0262 for (i = 8; i--;)
0263 v = v & 1 ? (v >> 1) ^ pattern : v >> 1;
0264 rtems_fdisk_crc16_factor[b] = v & 0xffff;
0265 }
0266 return RTEMS_SUCCESSFUL;
0267 }
0268
0269 #if RTEMS_FDISK_TRACE
0270
0271
0272
0273
0274
0275
0276
0277
0278 static int
0279 rtems_fdisk_printf (const rtems_flashdisk* fd, const char *format, ...)
0280 {
0281 int ret = 0;
0282 if (fd->info_level >= 3)
0283 {
0284 va_list args;
0285 va_start (args, format);
0286 fprintf (stdout, "fdisk:");
0287 ret = vfprintf (stdout, format, args);
0288 fprintf (stdout, "\n");
0289 fflush (stdout);
0290 va_end (args);
0291 }
0292 return ret;
0293 }
0294
0295 static bool
0296 rtems_fdisk_is_erased_blocks_starvation (rtems_flashdisk* fd)
0297 {
0298 bool starvation = fd->erased_blocks < fd->starvation_threshold;
0299
0300 if (starvation)
0301 fd->starvations++;
0302
0303 return starvation;
0304 }
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314 static int
0315 rtems_fdisk_info (const rtems_flashdisk* fd, const char *format, ...)
0316 {
0317 int ret = 0;
0318 if (fd->info_level >= 2)
0319 {
0320 va_list args;
0321 va_start (args, format);
0322 fprintf (stdout, "fdisk:");
0323 ret = vfprintf (stdout, format, args);
0324 fprintf (stdout, "\n");
0325 fflush (stdout);
0326 va_end (args);
0327 }
0328 return ret;
0329 }
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339 static int
0340 rtems_fdisk_warning (const rtems_flashdisk* fd, const char *format, ...)
0341 {
0342 int ret = 0;
0343 if (fd->info_level >= 1)
0344 {
0345 va_list args;
0346 va_start (args, format);
0347 fprintf (stdout, "fdisk:warning:");
0348 ret = vfprintf (stdout, format, args);
0349 fprintf (stdout, "\n");
0350 fflush (stdout);
0351 va_end (args);
0352 }
0353 return ret;
0354 }
0355 #endif
0356
0357
0358
0359
0360
0361
0362
0363
0364 static int
0365 rtems_fdisk_error (const char *format, ...)
0366 {
0367 int ret;
0368 va_list args;
0369 va_start (args, format);
0370 fprintf (stderr, "fdisk:error:");
0371 ret = vfprintf (stderr, format, args);
0372 fprintf (stderr, "\n");
0373 fflush (stderr);
0374 va_end (args);
0375 return ret;
0376 }
0377
0378
0379
0380
0381
0382
0383
0384 static void
0385 rtems_fdisk_abort (const char *format, ...)
0386 {
0387 va_list args;
0388 va_start (args, format);
0389 fprintf (stderr, "fdisk:abort:");
0390 vfprintf (stderr, format, args);
0391 fprintf (stderr, "\n");
0392 fflush (stderr);
0393 va_end (args);
0394 exit (1);
0395 }
0396
0397
0398
0399
0400 static void
0401 rtems_fdisk_segment_queue_init (rtems_fdisk_segment_ctl_queue* queue)
0402 {
0403 queue->head = queue->tail = 0;
0404 queue->count = 0;
0405 }
0406
0407
0408
0409
0410 static void
0411 rtems_fdisk_segment_queue_push_head (rtems_fdisk_segment_ctl_queue* queue,
0412 rtems_fdisk_segment_ctl* sc)
0413 {
0414 if (sc)
0415 {
0416 sc->next = queue->head;
0417 queue->head = sc;
0418
0419 if (queue->tail == 0)
0420 queue->tail = sc;
0421 queue->count++;
0422 }
0423 }
0424
0425
0426
0427
0428 static rtems_fdisk_segment_ctl*
0429 rtems_fdisk_segment_queue_pop_head (rtems_fdisk_segment_ctl_queue* queue)
0430 {
0431 if (queue->head)
0432 {
0433 rtems_fdisk_segment_ctl* sc = queue->head;
0434
0435 queue->head = sc->next;
0436 if (!queue->head)
0437 queue->tail = 0;
0438
0439 queue->count--;
0440
0441 sc->next = 0;
0442
0443 return sc;
0444 }
0445
0446 return 0;
0447 }
0448
0449
0450
0451
0452 static void
0453 rtems_fdisk_segment_queue_push_tail (rtems_fdisk_segment_ctl_queue* queue,
0454 rtems_fdisk_segment_ctl* sc)
0455 {
0456 if (sc)
0457 {
0458 sc->next = 0;
0459
0460 if (queue->head)
0461 {
0462 queue->tail->next = sc;
0463 queue->tail = sc;
0464 }
0465 else
0466 {
0467 queue->head = queue->tail = sc;
0468 }
0469
0470 queue->count++;
0471 }
0472 }
0473
0474
0475
0476
0477 static void
0478 rtems_fdisk_segment_queue_remove (rtems_fdisk_segment_ctl_queue* queue,
0479 rtems_fdisk_segment_ctl* sc)
0480 {
0481 rtems_fdisk_segment_ctl* prev = 0;
0482 rtems_fdisk_segment_ctl* it = queue->head;
0483
0484
0485
0486
0487
0488 while (it)
0489 {
0490 if (sc == it)
0491 {
0492 if (prev == 0)
0493 {
0494 queue->head = sc->next;
0495 if (queue->head == 0)
0496 queue->tail = 0;
0497 }
0498 else
0499 {
0500 prev->next = sc->next;
0501 if (queue->tail == sc)
0502 queue->tail = prev;
0503 }
0504 sc->next = 0;
0505 queue->count--;
0506 break;
0507 }
0508
0509 prev = it;
0510 it = it->next;
0511 }
0512 }
0513
0514
0515
0516
0517
0518 static void
0519 rtems_fdisk_segment_queue_insert_before (rtems_fdisk_segment_ctl_queue* queue,
0520 rtems_fdisk_segment_ctl* item,
0521 rtems_fdisk_segment_ctl* sc)
0522 {
0523 if (item)
0524 {
0525 rtems_fdisk_segment_ctl** prev = &queue->head;
0526 rtems_fdisk_segment_ctl* it = queue->head;
0527
0528 while (it)
0529 {
0530 if (item == it)
0531 {
0532 sc->next = item;
0533 *prev = sc;
0534 queue->count++;
0535 return;
0536 }
0537
0538 prev = &it->next;
0539 it = it->next;
0540 }
0541 }
0542
0543 rtems_fdisk_segment_queue_push_tail (queue, sc);
0544 }
0545
0546
0547
0548
0549 static uint32_t
0550 rtems_fdisk_segment_queue_count (rtems_fdisk_segment_ctl_queue* queue)
0551 {
0552 return queue->count;
0553 }
0554
0555
0556
0557
0558 static uint32_t
0559 rtems_fdisk_segment_count_queue (rtems_fdisk_segment_ctl_queue* queue)
0560 {
0561 rtems_fdisk_segment_ctl* sc = queue->head;
0562 uint32_t count = 0;
0563
0564 while (sc)
0565 {
0566 count++;
0567 sc = sc->next;
0568 }
0569
0570 return count;
0571 }
0572
0573
0574
0575
0576 static bool
0577 rtems_fdisk_segment_queue_present (rtems_fdisk_segment_ctl_queue* queue,
0578 rtems_fdisk_segment_ctl* sc)
0579 {
0580 rtems_fdisk_segment_ctl* it = queue->head;
0581
0582 while (it)
0583 {
0584 if (it == sc)
0585 return true;
0586 it = it->next;
0587 }
0588
0589 return false;
0590 }
0591
0592
0593
0594
0595 static void
0596 rtems_fdisk_queue_status (rtems_flashdisk* fd,
0597 rtems_fdisk_segment_ctl* sc,
0598 char queues[5])
0599 {
0600 queues[0] = rtems_fdisk_segment_queue_present (&fd->available, sc) ? 'A' : '-';
0601 queues[1] = rtems_fdisk_segment_queue_present (&fd->used, sc) ? 'U' : '-';
0602 queues[2] = rtems_fdisk_segment_queue_present (&fd->erase, sc) ? 'E' : '-';
0603 queues[3] = rtems_fdisk_segment_queue_present (&fd->failed, sc) ? 'F' : '-';
0604 queues[4] = '\0';
0605 }
0606
0607
0608
0609
0610 static bool
0611 rtems_fdisk_page_desc_erased (const rtems_fdisk_page_desc* pd)
0612 {
0613 return ((pd->crc == 0xffff) &&
0614 (pd->flags == 0xffff) &&
0615 (pd->block == 0xffffffff)) ? true : false;
0616 }
0617
0618
0619
0620
0621
0622 static bool
0623 rtems_fdisk_page_desc_flags_set (rtems_fdisk_page_desc* pd, uint16_t flags)
0624 {
0625 return (pd->flags & flags) == 0 ? true : false;
0626 }
0627
0628
0629
0630
0631
0632 static bool
0633 rtems_fdisk_page_desc_flags_clear (rtems_fdisk_page_desc* pd, uint16_t flags)
0634 {
0635 return (pd->flags & flags) == flags ? true : false;
0636 }
0637
0638
0639
0640
0641 static void
0642 rtems_fdisk_page_desc_set_flags (rtems_fdisk_page_desc* pd, uint16_t flags)
0643 {
0644 pd->flags &= ~flags;
0645 }
0646
0647
0648
0649
0650
0651 static const rtems_fdisk_segment_desc*
0652 rtems_fdisk_seg_descriptor (const rtems_flashdisk* fd,
0653 uint32_t device,
0654 uint32_t segment)
0655 {
0656 return fd->devices[device].segments[segment].descriptor;
0657 }
0658
0659
0660
0661
0662 static uint32_t
0663 rtems_fdisk_count_segments (const rtems_fdisk_device_desc* dd)
0664 {
0665 uint32_t count = 0;
0666 uint32_t segment;
0667 for (segment = 0; segment < dd->segment_count; segment++)
0668 count += dd->segments[segment].count;
0669 return count;
0670 }
0671
0672
0673
0674
0675
0676
0677
0678
0679 static uint32_t
0680 rtems_fdisk_pages_in_segment (const rtems_fdisk_segment_desc* sd,
0681 uint32_t page_size)
0682 {
0683 return sd->size / page_size;
0684 }
0685
0686
0687
0688
0689
0690
0691
0692
0693 static uint32_t
0694 rtems_fdisk_page_desc_pages (const rtems_fdisk_segment_desc* sd,
0695 uint32_t page_size)
0696 {
0697 uint32_t pages = rtems_fdisk_pages_in_segment (sd, page_size);
0698 uint32_t bytes = pages * sizeof (rtems_fdisk_page_desc);
0699 return ((bytes - 1) / page_size) + 1;
0700 }
0701
0702
0703
0704
0705
0706 static uint32_t
0707 rtems_fdisk_seg_pages_available (const rtems_fdisk_segment_ctl* sc)
0708 {
0709 return sc->pages - (sc->pages_active + sc->pages_used + sc->pages_bad);
0710 }
0711
0712
0713
0714 static uint32_t
0715 rtems_fdisk_seg_next_available_page (rtems_fdisk_segment_ctl* sc)
0716 {
0717 rtems_fdisk_page_desc* pd = &sc->page_descriptors[0];
0718 uint32_t page;
0719
0720 for (page = 0; page < sc->pages; page++, pd++)
0721 if (rtems_fdisk_page_desc_erased (pd))
0722 break;
0723
0724 return page;
0725 }
0726
0727
0728
0729
0730 static rtems_fdisk_segment_ctl*
0731 rtems_fdisk_seg_most_available (const rtems_fdisk_segment_ctl_queue* queue)
0732 {
0733 rtems_fdisk_segment_ctl* sc = queue->head;
0734 rtems_fdisk_segment_ctl* biggest = queue->head;
0735
0736 while (sc)
0737 {
0738 if (rtems_fdisk_seg_pages_available (sc) >
0739 rtems_fdisk_seg_pages_available (biggest))
0740 biggest = sc;
0741 sc = sc->next;
0742 }
0743
0744 return biggest;
0745 }
0746
0747
0748
0749
0750 #if 0
0751 static bool
0752 rtems_fdisk_seg_pages_all_used (const rtems_fdisk_segment_ctl* sc)
0753 {
0754 return sc->pages == (sc->pages_used + sc->pages_bad) ? true : false;
0755 }
0756 #endif
0757
0758
0759
0760
0761
0762
0763
0764
0765
0766
0767 static uint32_t
0768 rtems_fdisk_blocks_in_device (const rtems_fdisk_device_desc* dd,
0769 uint32_t page_size)
0770 {
0771 uint32_t count = 0;
0772 uint32_t s;
0773 for (s = 0; s < dd->segment_count; s++)
0774 {
0775 const rtems_fdisk_segment_desc* sd = &dd->segments[s];
0776 count +=
0777 (rtems_fdisk_pages_in_segment (sd, page_size) -
0778 rtems_fdisk_page_desc_pages (sd, page_size)) * sd->count;
0779 }
0780 return count;
0781 }
0782
0783
0784
0785
0786 static int
0787 rtems_fdisk_seg_read (const rtems_flashdisk* fd,
0788 const rtems_fdisk_segment_ctl* sc,
0789 uint32_t offset,
0790 void* buffer,
0791 uint32_t size)
0792 {
0793 uint32_t device;
0794 uint32_t segment;
0795 const rtems_fdisk_segment_desc* sd;
0796 const rtems_fdisk_driver_handlers* ops;
0797 device = sc->device;
0798 segment = sc->segment;
0799 sd = rtems_fdisk_seg_descriptor (fd, device, segment);
0800 ops = fd->devices[device].descriptor->flash_ops;
0801 #if RTEMS_FDISK_TRACE
0802 rtems_fdisk_printf (fd, " seg-read: %02d-%03d: o=%08x s=%d",
0803 device, segment, offset, size);
0804 #endif
0805 return ops->read (sd, device, segment, offset, buffer, size);
0806 }
0807
0808
0809
0810
0811
0812
0813 static int
0814 rtems_fdisk_seg_write (const rtems_flashdisk* fd,
0815 rtems_fdisk_segment_ctl* sc,
0816 uint32_t offset,
0817 const void* buffer,
0818 uint32_t size)
0819 {
0820 int ret;
0821 uint32_t device;
0822 uint32_t segment;
0823 const rtems_fdisk_segment_desc* sd;
0824 const rtems_fdisk_driver_handlers* ops;
0825 device = sc->device;
0826 segment = sc->segment;
0827 sd = rtems_fdisk_seg_descriptor (fd, device, segment);
0828 ops = fd->devices[device].descriptor->flash_ops;
0829 #if RTEMS_FDISK_TRACE
0830 rtems_fdisk_printf (fd, " seg-write: %02d-%03d: o=%08x s=%d",
0831 device, segment, offset, size);
0832 #endif
0833 ret = ops->write (sd, device, segment, offset, buffer, size);
0834 if (ret)
0835 sc->failed = true;
0836
0837 return ret;
0838 }
0839
0840
0841
0842
0843 static int
0844 rtems_fdisk_seg_blank_check (const rtems_flashdisk* fd,
0845 rtems_fdisk_segment_ctl* sc,
0846 uint32_t offset,
0847 uint32_t size)
0848 {
0849 uint32_t device;
0850 uint32_t segment;
0851 const rtems_fdisk_segment_desc* sd;
0852 const rtems_fdisk_driver_handlers* ops;
0853 device = sc->device;
0854 segment = sc->segment;
0855 sd = rtems_fdisk_seg_descriptor (fd, device, segment);
0856 ops = fd->devices[device].descriptor->flash_ops;
0857 #if RTEMS_FDISK_TRACE
0858 rtems_fdisk_printf (fd, " seg-blank: %02d-%03d: o=%08x s=%d",
0859 device, segment, offset, size);
0860 #endif
0861 return ops->blank (sd, device, segment, offset, size);
0862 }
0863
0864
0865
0866 static int
0867 rtems_fdisk_seg_verify (const rtems_flashdisk* fd,
0868 uint32_t device,
0869 uint32_t segment,
0870 uint32_t offset,
0871 const void* buffer,
0872 uint32_t size)
0873 {
0874 const rtems_fdisk_segment_desc* sd;
0875 const rtems_fdisk_driver_handlers* ops;
0876 sd = rtems_fdisk_seg_descriptor (fd, device, segment);
0877 ops = fd->devices[device].descriptor->flash_ops;
0878 #if RTEMS_FDISK_TRACE
0879 rtems_fdisk_printf (fd, " seg-verify: %02d-%03d: o=%08x s=%d",
0880 device, segment, offset, size);
0881 #endif
0882 return ops->verify (sd, device, segment, offset, buffer, size);
0883 }
0884
0885
0886
0887
0888 static int
0889 rtems_fdisk_seg_blank_check_page (const rtems_flashdisk* fd,
0890 rtems_fdisk_segment_ctl* sc,
0891 uint32_t page)
0892 {
0893 return rtems_fdisk_seg_blank_check (fd, sc,
0894 page * fd->block_size, fd->block_size);
0895 }
0896
0897
0898
0899
0900 static int
0901 rtems_fdisk_seg_read_page (const rtems_flashdisk* fd,
0902 rtems_fdisk_segment_ctl* sc,
0903 uint32_t page,
0904 void* buffer)
0905 {
0906 return rtems_fdisk_seg_read (fd, sc,
0907 page * fd->block_size, buffer, fd->block_size);
0908 }
0909
0910
0911
0912
0913 static int
0914 rtems_fdisk_seg_write_page (rtems_flashdisk* fd,
0915 rtems_fdisk_segment_ctl* sc,
0916 uint32_t page,
0917 const void* buffer)
0918 {
0919 if ((fd->flags & RTEMS_FDISK_BLANK_CHECK_BEFORE_WRITE))
0920 {
0921 int ret = rtems_fdisk_seg_blank_check_page (fd, sc, page);
0922 if (ret)
0923 return ret;
0924 }
0925 --fd->erased_blocks;
0926 return rtems_fdisk_seg_write (fd, sc,
0927 page * fd->block_size, buffer, fd->block_size);
0928 }
0929
0930
0931
0932
0933 static int
0934 rtems_fdisk_seg_verify_page (const rtems_flashdisk* fd,
0935 uint32_t device,
0936 uint32_t segment,
0937 uint32_t page,
0938 const void* buffer)
0939 {
0940 return rtems_fdisk_seg_verify (fd, device, segment,
0941 page * fd->block_size, buffer, fd->block_size);
0942 }
0943
0944
0945
0946
0947 static int
0948 rtems_fdisk_seg_copy_page (rtems_flashdisk* fd,
0949 rtems_fdisk_segment_ctl* src_sc,
0950 uint32_t src_page,
0951 rtems_fdisk_segment_ctl* dst_sc,
0952 uint32_t dst_page)
0953 {
0954 int ret;
0955 #if RTEMS_FDISK_TRACE
0956 rtems_fdisk_printf (fd, " seg-copy-page: %02d-%03d~%03d=>%02d-%03d~%03d",
0957 src_sc->device, src_sc->segment, src_page,
0958 dst_sc->device, dst_sc->segment, dst_page);
0959 #endif
0960 ret = rtems_fdisk_seg_read_page (fd, src_sc, src_page,
0961 fd->copy_buffer);
0962 if (ret)
0963 return ret;
0964 return rtems_fdisk_seg_write_page (fd, dst_sc, dst_page,
0965 fd->copy_buffer);
0966 }
0967
0968
0969
0970
0971
0972 static int
0973 rtems_fdisk_seg_write_page_desc (const rtems_flashdisk* fd,
0974 rtems_fdisk_segment_ctl* sc,
0975 uint32_t page,
0976 const rtems_fdisk_page_desc* page_desc)
0977 {
0978 uint32_t offset = page * sizeof (rtems_fdisk_page_desc);
0979 if ((fd->flags & RTEMS_FDISK_BLANK_CHECK_BEFORE_WRITE))
0980 {
0981 int ret = rtems_fdisk_seg_blank_check (fd, sc,
0982 offset,
0983 sizeof (rtems_fdisk_page_desc));
0984 if (ret)
0985 return ret;
0986 }
0987 return rtems_fdisk_seg_write (fd, sc, offset,
0988 page_desc, sizeof (rtems_fdisk_page_desc));
0989 }
0990
0991
0992
0993
0994
0995 static int
0996 rtems_fdisk_seg_write_page_desc_flags (const rtems_flashdisk* fd,
0997 rtems_fdisk_segment_ctl* sc,
0998 uint32_t page,
0999 const rtems_fdisk_page_desc* page_desc)
1000 {
1001 uint32_t offset = ((page * sizeof (rtems_fdisk_page_desc)) +
1002 ((uint8_t*) &page_desc->flags) - ((uint8_t*) page_desc));
1003 if ((fd->flags & RTEMS_FDISK_BLANK_CHECK_BEFORE_WRITE))
1004 {
1005 uint16_t flash_flags;
1006 int ret;
1007 ret = rtems_fdisk_seg_read (fd, sc, offset,
1008 &flash_flags, sizeof (flash_flags));
1009 if (ret)
1010 return ret;
1011 if ((flash_flags & page_desc->flags) != page_desc->flags)
1012 {
1013 rtems_fdisk_error (" seg-write-page-flags: %02d-%03d-%03d: "
1014 "flags not erased: 0x%04x-> 0x%04x",
1015 sc->device, sc->segment, page,
1016 flash_flags, page_desc->flags);
1017 return ret;
1018 }
1019 }
1020 return rtems_fdisk_seg_write (fd, sc, offset,
1021 &page_desc->flags, sizeof (page_desc->flags));
1022 }
1023
1024
1025
1026
1027 static int
1028 rtems_fdisk_device_erase (const rtems_flashdisk* fd, uint32_t device)
1029 {
1030 const rtems_fdisk_driver_handlers* ops;
1031 ops = fd->devices[device].descriptor->flash_ops;
1032 #if RTEMS_FDISK_TRACE
1033 rtems_fdisk_printf (fd, " device-erase: %02d", device);
1034 #endif
1035 return ops->erase_device (fd->devices[device].descriptor, device);
1036 }
1037
1038
1039
1040
1041 static int
1042 rtems_fdisk_erase_flash (const rtems_flashdisk* fd)
1043 {
1044 uint32_t device;
1045 for (device = 0; device < fd->device_count; device++)
1046 {
1047 int ret;
1048
1049 #if RTEMS_FDISK_TRACE
1050 rtems_fdisk_info (fd, " erase-flash:%02d", device);
1051 #endif
1052
1053 ret = rtems_fdisk_device_erase (fd, device);
1054
1055 if (ret != 0)
1056 return ret;
1057 }
1058 return 0;
1059 }
1060
1061
1062
1063
1064 static uint16_t
1065 rtems_fdisk_page_checksum (const uint8_t* buffer, uint32_t page_size)
1066 {
1067 uint16_t cs = 0xffff;
1068 uint32_t i;
1069
1070 for (i = 0; i < page_size; i++, buffer++)
1071 cs = rtems_fdisk_calc_crc16 (*buffer, cs);
1072
1073 return cs;
1074 }
1075
1076
1077
1078
1079 static int
1080 rtems_fdisk_erase_segment (rtems_flashdisk* fd, rtems_fdisk_segment_ctl* sc)
1081 {
1082 int ret;
1083 uint32_t device;
1084 uint32_t segment;
1085 const rtems_fdisk_segment_desc* sd;
1086 const rtems_fdisk_driver_handlers* ops;
1087 device = sc->device;
1088 segment = sc->segment;
1089 sd = rtems_fdisk_seg_descriptor (fd, device, segment);
1090 ops = fd->devices[device].descriptor->flash_ops;
1091 ret = ops->erase (sd, device, segment);
1092 if (ret)
1093 {
1094 rtems_fdisk_error (" erase-segment:%02d-%03d: " \
1095 "segment erase failed: %s (%d)",
1096 sc->device, sc->segment, strerror (ret), ret);
1097 sc->failed = true;
1098 if (!rtems_fdisk_segment_queue_present (&fd->failed, sc))
1099 rtems_fdisk_segment_queue_push_tail (&fd->failed, sc);
1100 return ret;
1101 }
1102
1103 fd->erased_blocks += sc->pages;
1104 sc->erased++;
1105
1106 memset (sc->page_descriptors, 0xff, sc->pages_desc * fd->block_size);
1107
1108 sc->pages_active = 0;
1109 sc->pages_used = 0;
1110 sc->pages_bad = 0;
1111
1112 sc->failed = false;
1113
1114
1115
1116
1117
1118
1119 rtems_fdisk_segment_queue_push_tail (&fd->available, sc);
1120
1121 return 0;
1122 }
1123
1124
1125
1126
1127 static int
1128 rtems_fdisk_erase_used (rtems_flashdisk* fd)
1129 {
1130 rtems_fdisk_segment_ctl* sc;
1131 int latched_ret = 0;
1132
1133 while ((sc = rtems_fdisk_segment_queue_pop_head (&fd->erase)))
1134 {
1135
1136
1137
1138
1139 int ret = rtems_fdisk_erase_segment (fd, sc);
1140 if (ret && !latched_ret)
1141 latched_ret = ret;
1142 }
1143
1144 return latched_ret;
1145 }
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155 static void
1156 rtems_fdisk_queue_segment (rtems_flashdisk* fd, rtems_fdisk_segment_ctl* sc)
1157 {
1158 #if RTEMS_FDISK_TRACE
1159 rtems_fdisk_info (fd, " queue-seg:%02d-%03d: p=%d a=%d u=%d b=%d f=%s n=%s",
1160 sc->device, sc->segment,
1161 sc->pages, sc->pages_active, sc->pages_used, sc->pages_bad,
1162 sc->failed ? "FAILED" : "no", sc->next ? "set" : "null");
1163 #endif
1164
1165
1166
1167
1168
1169 if (sc->failed)
1170 {
1171 if (!rtems_fdisk_segment_queue_present (&fd->failed, sc))
1172 rtems_fdisk_segment_queue_push_tail (&fd->failed, sc);
1173 return;
1174 }
1175
1176
1177
1178
1179 rtems_fdisk_segment_queue_remove (&fd->available, sc);
1180 rtems_fdisk_segment_queue_remove (&fd->used, sc);
1181
1182
1183
1184
1185
1186
1187
1188
1189 if (rtems_fdisk_seg_pages_available (sc) == 0)
1190 {
1191 if (sc->pages_active)
1192 {
1193
1194
1195
1196
1197
1198 rtems_fdisk_segment_ctl* seg = fd->used.head;
1199
1200 while (seg)
1201 {
1202 if (sc->pages_used > seg->pages_used)
1203 break;
1204 seg = seg->next;
1205 }
1206
1207 if (seg)
1208 rtems_fdisk_segment_queue_insert_before (&fd->used, seg, sc);
1209 else
1210 rtems_fdisk_segment_queue_push_tail (&fd->used, sc);
1211 }
1212 else
1213 {
1214 if ((fd->flags & RTEMS_FDISK_BACKGROUND_ERASE))
1215 rtems_fdisk_segment_queue_push_tail (&fd->erase, sc);
1216 else
1217 rtems_fdisk_erase_segment (fd, sc);
1218 }
1219 }
1220 else
1221 {
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248 rtems_fdisk_segment_ctl* seg = fd->available.head;
1249
1250 while (seg)
1251 {
1252 if (rtems_fdisk_seg_pages_available (sc) <
1253 rtems_fdisk_seg_pages_available (seg))
1254 break;
1255 seg = seg->next;
1256 }
1257
1258 if (seg)
1259 rtems_fdisk_segment_queue_insert_before (&fd->available, seg, sc);
1260 else
1261 rtems_fdisk_segment_queue_push_tail (&fd->available, sc);
1262 }
1263 }
1264
1265 static int
1266 rtems_fdisk_recycle_segment (rtems_flashdisk* fd,
1267 rtems_fdisk_segment_ctl* ssc,
1268 rtems_fdisk_segment_ctl* dsc,
1269 uint32_t *pages)
1270 {
1271 int ret;
1272 uint32_t spage;
1273 uint32_t used = 0;
1274 uint32_t active = 0;
1275
1276 for (spage = 0; spage < ssc->pages; spage++)
1277 {
1278 rtems_fdisk_page_desc* spd = &ssc->page_descriptors[spage];
1279
1280 if (rtems_fdisk_page_desc_flags_set (spd, RTEMS_FDISK_PAGE_ACTIVE) &&
1281 !rtems_fdisk_page_desc_flags_set (spd, RTEMS_FDISK_PAGE_USED))
1282 {
1283 uint32_t dst_pages;
1284 rtems_fdisk_page_desc* dpd;
1285 uint32_t dpage;
1286
1287 dpage = rtems_fdisk_seg_next_available_page (dsc);
1288 dpd = &dsc->page_descriptors[dpage];
1289
1290 active++;
1291
1292 if (dpage >= dsc->pages)
1293 {
1294 rtems_fdisk_error ("recycle: %02d-%03d: " \
1295 "no page desc available: %d",
1296 dsc->device, dsc->segment,
1297 rtems_fdisk_seg_pages_available (dsc));
1298 dsc->failed = true;
1299 rtems_fdisk_queue_segment (fd, dsc);
1300 rtems_fdisk_segment_queue_push_head (&fd->used, ssc);
1301 return EIO;
1302 }
1303
1304 #if RTEMS_FDISK_TRACE
1305 rtems_fdisk_info (fd, "recycle: %02d-%03d-%03d=>%02d-%03d-%03d",
1306 ssc->device, ssc->segment, spage,
1307 dsc->device, dsc->segment, dpage);
1308 #endif
1309 ret = rtems_fdisk_seg_copy_page (fd, ssc,
1310 spage + ssc->pages_desc,
1311 dsc,
1312 dpage + dsc->pages_desc);
1313 if (ret)
1314 {
1315 rtems_fdisk_error ("recycle: %02d-%03d-%03d=>" \
1316 "%02d-%03d-%03d: " \
1317 "copy page failed: %s (%d)",
1318 ssc->device, ssc->segment, spage,
1319 dsc->device, dsc->segment, dpage,
1320 strerror (ret), ret);
1321 rtems_fdisk_queue_segment (fd, dsc);
1322 rtems_fdisk_segment_queue_push_head (&fd->used, ssc);
1323 return ret;
1324 }
1325
1326 *dpd = *spd;
1327
1328 ret = rtems_fdisk_seg_write_page_desc (fd,
1329 dsc,
1330 dpage, dpd);
1331
1332 if (ret)
1333 {
1334 rtems_fdisk_error ("recycle: %02d-%03d-%03d=>" \
1335 "%02d-%03d-%03d: copy pd failed: %s (%d)",
1336 ssc->device, ssc->segment, spage,
1337 dsc->device, dsc->segment, dpage,
1338 strerror (ret), ret);
1339 rtems_fdisk_queue_segment (fd, dsc);
1340 rtems_fdisk_segment_queue_push_head (&fd->used, ssc);
1341 return ret;
1342 }
1343
1344 dsc->pages_active++;
1345
1346
1347
1348
1349
1350
1351
1352
1353 ssc->pages_active--;
1354 ssc->pages_used++;
1355
1356 fd->blocks[spd->block].segment = dsc;
1357 fd->blocks[spd->block].page = dpage;
1358
1359
1360
1361
1362 rtems_fdisk_queue_segment (fd, dsc);
1363
1364
1365
1366
1367 dst_pages = rtems_fdisk_seg_pages_available (dsc);
1368 if (dst_pages == 0)
1369 {
1370 dsc = rtems_fdisk_seg_most_available (&fd->available);
1371 if (!dsc)
1372 {
1373 if (ssc->pages_active == 0)
1374 {
1375 ret = rtems_fdisk_erase_segment (fd, ssc);
1376 }
1377 else
1378 {
1379 rtems_fdisk_error ("recycle: no available dst segment");
1380 ret = EIO;
1381 }
1382
1383 return ret;
1384 }
1385 }
1386
1387 (*pages)--;
1388 }
1389 else if (rtems_fdisk_page_desc_erased (spd))
1390 {
1391 --fd->erased_blocks;
1392 }
1393 else
1394 {
1395 used++;
1396 }
1397 }
1398
1399 #if RTEMS_FDISK_TRACE
1400 rtems_fdisk_printf (fd, "ssc end: %d-%d: p=%ld, a=%ld, u=%ld",
1401 ssc->device, ssc->segment,
1402 pages, active, used);
1403 #endif
1404 if (ssc->pages_active != 0)
1405 {
1406 rtems_fdisk_error ("compacting: ssc pages not 0: %d",
1407 ssc->pages_active);
1408 }
1409
1410 ret = rtems_fdisk_erase_segment (fd, ssc);
1411
1412 return ret;
1413 }
1414
1415
1416
1417
1418
1419
1420
1421 static int
1422 rtems_fdisk_compact (rtems_flashdisk* fd)
1423 {
1424 int ret;
1425 rtems_fdisk_segment_ctl* dsc;
1426 rtems_fdisk_segment_ctl* ssc;
1427 uint32_t compacted_segs = 0;
1428 uint32_t pages;
1429
1430 if (rtems_fdisk_is_erased_blocks_starvation (fd))
1431 {
1432 #if RTEMS_FDISK_TRACE
1433 rtems_fdisk_printf (fd, " resolve starvation");
1434 #endif
1435
1436 ssc = rtems_fdisk_segment_queue_pop_head (&fd->used);
1437 if (!ssc)
1438 ssc = rtems_fdisk_segment_queue_pop_head (&fd->available);
1439
1440 if (ssc)
1441 {
1442 dsc = rtems_fdisk_seg_most_available (&fd->available);
1443 if (dsc)
1444 {
1445 ret = rtems_fdisk_recycle_segment (fd, ssc, dsc, &pages);
1446 if (ret)
1447 return ret;
1448 }
1449 else
1450 {
1451 rtems_fdisk_error ("compacting: starvation");
1452 return EIO;
1453 }
1454 }
1455 else
1456 {
1457 rtems_fdisk_error ("compacting: nothing to recycle");
1458 return EIO;
1459 }
1460 }
1461
1462 while (fd->used.head)
1463 {
1464 uint32_t dst_pages;
1465 uint32_t segments;
1466
1467 #if RTEMS_FDISK_TRACE
1468 rtems_fdisk_printf (fd, " compacting");
1469 #endif
1470
1471 dsc = rtems_fdisk_seg_most_available (&fd->available);
1472
1473 if (dsc == 0)
1474 {
1475 rtems_fdisk_error ("compacting: no available segments to compact too");
1476 return EIO;
1477 }
1478
1479 ssc = fd->used.head;
1480 dst_pages = rtems_fdisk_seg_pages_available (dsc);
1481 segments = 0;
1482 pages = 0;
1483
1484 #if RTEMS_FDISK_TRACE
1485 rtems_fdisk_printf (fd, " dsc:%02d-%03d: most available",
1486 dsc->device, dsc->segment);
1487 #endif
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497 while (ssc &&
1498 ((pages + ssc->pages_active) < dst_pages) &&
1499 ((compacted_segs + segments) < fd->compact_segs))
1500 {
1501 pages += ssc->pages_active;
1502 segments++;
1503 ssc = ssc->next;
1504 }
1505
1506
1507
1508
1509
1510
1511
1512 if (!ssc || (pages == 0) || ((compacted_segs + segments) == 1))
1513 {
1514 #if RTEMS_FDISK_TRACE
1515 rtems_fdisk_printf (fd, " nothing to compact");
1516 #endif
1517 break;
1518 }
1519
1520 #if RTEMS_FDISK_TRACE
1521 rtems_fdisk_printf (fd, " ssc scan: %d-%d: p=%ld, seg=%ld",
1522 ssc->device, ssc->segment,
1523 pages, segments);
1524 #endif
1525
1526 rtems_fdisk_segment_queue_remove (&fd->available, dsc);
1527
1528
1529
1530
1531
1532 while (pages)
1533 {
1534 ssc = rtems_fdisk_segment_queue_pop_head (&fd->used);
1535
1536 if (ssc)
1537 {
1538 ret = rtems_fdisk_recycle_segment (fd, ssc, dsc, &pages);
1539 if (ret)
1540 return ret;
1541 }
1542 }
1543
1544 compacted_segs += segments;
1545 }
1546
1547 return 0;
1548 }
1549
1550
1551
1552
1553 static int
1554 rtems_fdisk_recover_block_mappings (rtems_flashdisk* fd)
1555 {
1556 uint32_t device;
1557
1558
1559
1560
1561 rtems_fdisk_segment_queue_init (&fd->available);
1562 rtems_fdisk_segment_queue_init (&fd->used);
1563 rtems_fdisk_segment_queue_init (&fd->erase);
1564 rtems_fdisk_segment_queue_init (&fd->failed);
1565
1566
1567
1568
1569 memset (fd->blocks, 0, fd->block_count * sizeof (rtems_fdisk_block_ctl));
1570
1571
1572
1573
1574 fd->erased_blocks = 0;
1575 fd->starvation_threshold = 0;
1576 for (device = 0; device < fd->device_count; device++)
1577 {
1578 uint32_t segment;
1579 for (segment = 0; segment < fd->devices[device].segment_count; segment++)
1580 {
1581 rtems_fdisk_segment_ctl* sc = &fd->devices[device].segments[segment];
1582 const rtems_fdisk_segment_desc* sd = sc->descriptor;
1583 rtems_fdisk_page_desc* pd;
1584 uint32_t page;
1585 int ret;
1586
1587 #if RTEMS_FDISK_TRACE
1588 rtems_fdisk_info (fd, "recover-block-mappings:%02d-%03d", device, segment);
1589 #endif
1590
1591 sc->pages_desc = rtems_fdisk_page_desc_pages (sd, fd->block_size);
1592 sc->pages =
1593 rtems_fdisk_pages_in_segment (sd, fd->block_size) - sc->pages_desc;
1594 if (sc->pages > fd->starvation_threshold)
1595 fd->starvation_threshold = sc->pages;
1596
1597 sc->pages_active = 0;
1598 sc->pages_used = 0;
1599 sc->pages_bad = 0;
1600
1601 sc->failed = false;
1602
1603 if (!sc->page_descriptors)
1604 sc->page_descriptors = malloc (sc->pages_desc * fd->block_size);
1605
1606 if (!sc->page_descriptors)
1607 rtems_fdisk_abort ("no memory for page descriptors");
1608
1609 pd = sc->page_descriptors;
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619 ret = rtems_fdisk_seg_read (fd, sc, 0, (void*) pd,
1620 sc->pages_desc * fd->block_size);
1621
1622 if (ret)
1623 {
1624 rtems_fdisk_error ("recover-block-mappings:%02d-%03d: " \
1625 "read page desc failed: %s (%d)",
1626 device, segment, strerror (ret), ret);
1627 return ret;
1628 }
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638 for (page = 0; page < sc->pages; page++, pd++)
1639 {
1640 if (rtems_fdisk_page_desc_erased (pd))
1641 {
1642
1643
1644
1645 ret = rtems_fdisk_seg_blank_check_page (fd, sc,
1646 page + sc->pages_desc);
1647
1648 if (ret == 0)
1649 {
1650 ++fd->erased_blocks;
1651 }
1652 else
1653 {
1654 #if RTEMS_FDISK_TRACE
1655 rtems_fdisk_warning (fd, "page not blank: %d-%d-%d",
1656 device, segment, page, pd->block);
1657 #endif
1658 rtems_fdisk_page_desc_set_flags (pd, RTEMS_FDISK_PAGE_USED);
1659
1660 ret = rtems_fdisk_seg_write_page_desc (fd, sc,
1661 page, pd);
1662
1663 if (ret)
1664 {
1665 rtems_fdisk_error ("forcing page to used failed: %d-%d-%d",
1666 device, segment, page);
1667 }
1668
1669 sc->pages_used++;
1670 }
1671 }
1672 else
1673 {
1674 if (rtems_fdisk_page_desc_flags_set (pd, RTEMS_FDISK_PAGE_USED))
1675 {
1676 sc->pages_used++;
1677 }
1678 else if (rtems_fdisk_page_desc_flags_set (pd, RTEMS_FDISK_PAGE_ACTIVE))
1679 {
1680 if (pd->block >= fd->block_count)
1681 {
1682 #if RTEMS_FDISK_TRACE
1683 rtems_fdisk_warning (fd,
1684 "invalid block number: %d-%d-%d: block: %d",
1685 device, segment, page, pd->block);
1686 #endif
1687 sc->pages_bad++;
1688 }
1689 else if (fd->blocks[pd->block].segment)
1690 {
1691
1692
1693
1694
1695
1696
1697
1698 const rtems_fdisk_segment_ctl* bsc = fd->blocks[pd->block].segment;
1699 rtems_fdisk_error ("duplicate block: %d-%d-%d: " \
1700 "duplicate: %d-%d-%d",
1701 bsc->device, bsc->segment,
1702 fd->blocks[pd->block].page,
1703 device, segment, page);
1704 sc->pages_bad++;
1705 }
1706 else
1707 {
1708
1709
1710
1711
1712 fd->blocks[pd->block].segment = sc;
1713 fd->blocks[pd->block].page = page;
1714
1715
1716
1717
1718 sc->pages_active++;
1719 }
1720 }
1721 else
1722 sc->pages_bad++;
1723 }
1724 }
1725
1726
1727
1728
1729 rtems_fdisk_queue_segment (fd, sc);
1730 }
1731 }
1732
1733 return 0;
1734 }
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747 static bool
1748 rtems_fdisk_read_block (rtems_flashdisk* fd,
1749 uint32_t block,
1750 uint8_t* buffer)
1751 {
1752 rtems_fdisk_block_ctl* bc;
1753 rtems_fdisk_segment_ctl* sc;
1754 rtems_fdisk_page_desc* pd;
1755
1756 #if RTEMS_FDISK_TRACE
1757 rtems_fdisk_info (fd, "read-block:%d", block);
1758 #endif
1759
1760
1761
1762
1763
1764 if (block >= (fd->block_count - fd->unavail_blocks))
1765 {
1766 rtems_fdisk_error ("read-block: block out of range: %d", block);
1767 return EIO;
1768 }
1769
1770 bc = &fd->blocks[block];
1771
1772 if (!bc->segment)
1773 {
1774 #if RTEMS_FDISK_TRACE
1775 rtems_fdisk_info (fd, "read-block: no segment mapping: %d", block);
1776 #endif
1777 memset (buffer, 0xff, fd->block_size);
1778 return 0;
1779 }
1780
1781 sc = fd->blocks[block].segment;
1782 pd = &sc->page_descriptors[bc->page];
1783
1784 #if RTEMS_FDISK_TRACE
1785 rtems_fdisk_info (fd,
1786 " read:%d=>%02d-%03d-%03d: p=%d a=%d u=%d b=%d n=%s: " \
1787 "f=%04x c=%04x b=%d",
1788 block, sc->device, sc->segment, bc->page,
1789 sc->pages, sc->pages_active, sc->pages_used, sc->pages_bad,
1790 sc->next ? "set" : "null",
1791 pd->flags, pd->crc, pd->block);
1792 #endif
1793
1794 if (rtems_fdisk_page_desc_flags_set (pd, RTEMS_FDISK_PAGE_ACTIVE))
1795 {
1796 if (rtems_fdisk_page_desc_flags_clear (pd, RTEMS_FDISK_PAGE_USED))
1797 {
1798 uint16_t cs;
1799
1800
1801
1802
1803
1804 int ret = rtems_fdisk_seg_read_page (fd, sc,
1805 bc->page + sc->pages_desc, buffer);
1806
1807 if (ret)
1808 {
1809 #if RTEMS_FDISK_TRACE
1810 rtems_fdisk_info (fd,
1811 "read-block:%02d-%03d-%03d: read page failed: %s (%d)",
1812 sc->device, sc->segment, bc->page,
1813 strerror (ret), ret);
1814 #endif
1815 return ret;
1816 }
1817
1818 cs = rtems_fdisk_page_checksum (buffer, fd->block_size);
1819
1820 if (cs == pd->crc)
1821 return 0;
1822
1823 rtems_fdisk_error ("read-block: crc failure: %d: buffer:%04x page:%04x",
1824 block, cs, pd->crc);
1825 }
1826 else
1827 {
1828 rtems_fdisk_error ("read-block: block points to used page: %d: %d-%d-%d",
1829 block, sc->device, sc->segment, bc->page);
1830 }
1831 }
1832 else
1833 {
1834 rtems_fdisk_error ("read-block: block page not active: %d: %d-%d-%d",
1835 block, sc->device, sc->segment, bc->page);
1836 }
1837
1838 return EIO;
1839 }
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866 static int
1867 rtems_fdisk_write_block (rtems_flashdisk* fd,
1868 uint32_t block,
1869 const uint8_t* buffer)
1870 {
1871 rtems_fdisk_block_ctl* bc;
1872 rtems_fdisk_segment_ctl* sc;
1873 rtems_fdisk_page_desc* pd;
1874 uint32_t page;
1875 int ret;
1876
1877 #if RTEMS_FDISK_TRACE
1878 rtems_fdisk_info (fd, "write-block:%d", block);
1879 #endif
1880
1881
1882
1883
1884
1885 if (block >= (fd->block_count - fd->unavail_blocks))
1886 {
1887 rtems_fdisk_error ("write-block: block out of range: %d", block);
1888 return EIO;
1889 }
1890
1891 bc = &fd->blocks[block];
1892
1893
1894
1895
1896 if (bc->segment)
1897 {
1898 sc = bc->segment;
1899 pd = &sc->page_descriptors[bc->page];
1900
1901 #if RTEMS_FDISK_TRACE
1902 rtems_fdisk_info (fd, " write:%02d-%03d-%03d: flag used",
1903 sc->device, sc->segment, bc->page);
1904 #endif
1905
1906
1907
1908
1909 if (rtems_fdisk_seg_verify_page (fd, sc->device, sc->segment,
1910 bc->page + sc->pages_desc, buffer) == 0)
1911 {
1912 #if RTEMS_FDISK_TRACE
1913 rtems_fdisk_info (fd, "write-block:%d=>%02d-%03d-%03d: page verified",
1914 block, sc->device, sc->segment, bc->page);
1915 #endif
1916 return 0;
1917 }
1918
1919
1920
1921
1922
1923
1924
1925
1926 rtems_fdisk_page_desc_set_flags (pd, RTEMS_FDISK_PAGE_USED);
1927
1928 ret = rtems_fdisk_seg_write_page_desc_flags (fd, sc, bc->page, pd);
1929
1930 if (ret)
1931 {
1932 #if RTEMS_FDISK_TRACE
1933 rtems_fdisk_info (fd, " write:%02d-%03d-%03d: " \
1934 "write used page desc failed: %s (%d)",
1935 sc->device, sc->segment, bc->page,
1936 strerror (ret), ret);
1937 #endif
1938 }
1939 else
1940 {
1941 sc->pages_active--;
1942 sc->pages_used++;
1943 }
1944
1945
1946
1947
1948
1949
1950 rtems_fdisk_queue_segment (fd, sc);
1951
1952
1953
1954
1955
1956
1957 if ((fd->flags & RTEMS_FDISK_BACKGROUND_COMPACT) == 0)
1958 rtems_fdisk_compact (fd);
1959 }
1960
1961
1962
1963
1964
1965
1966 if (rtems_fdisk_segment_count_queue (&fd->available) <=
1967 fd->avail_compact_segs)
1968 rtems_fdisk_compact (fd);
1969
1970
1971
1972
1973 sc = rtems_fdisk_segment_queue_pop_head (&fd->available);
1974
1975
1976
1977
1978 if (!sc)
1979 {
1980
1981
1982
1983
1984 if ((fd->flags & RTEMS_FDISK_BACKGROUND_COMPACT))
1985 rtems_fdisk_compact (fd);
1986
1987
1988
1989
1990 sc = rtems_fdisk_segment_queue_pop_head (&fd->available);
1991
1992 if (!sc)
1993 {
1994 rtems_fdisk_error ("write-block: no available pages");
1995 return ENOSPC;
1996 }
1997 }
1998
1999 #if RTEMS_FDISK_TRACE
2000 if (fd->info_level >= 3)
2001 {
2002 char queues[5];
2003 rtems_fdisk_queue_status (fd, sc, queues);
2004 rtems_fdisk_info (fd, " write:%d=>%02d-%03d: queue check: %s",
2005 block, sc->device, sc->segment, queues);
2006 }
2007 #endif
2008
2009
2010
2011
2012
2013 pd = sc->page_descriptors;
2014
2015 for (page = 0; page < sc->pages; page++, pd++)
2016 {
2017 if (rtems_fdisk_page_desc_erased (pd))
2018 {
2019 pd->crc = rtems_fdisk_page_checksum (buffer, fd->block_size);
2020 pd->block = block;
2021
2022 bc->segment = sc;
2023 bc->page = page;
2024
2025 rtems_fdisk_page_desc_set_flags (pd, RTEMS_FDISK_PAGE_ACTIVE);
2026
2027 #if RTEMS_FDISK_TRACE
2028 rtems_fdisk_info (fd, " write:%d=>%02d-%03d-%03d: write: " \
2029 "p=%d a=%d u=%d b=%d n=%s: f=%04x c=%04x b=%d",
2030 block, sc->device, sc->segment, page,
2031 sc->pages, sc->pages_active, sc->pages_used,
2032 sc->pages_bad, sc->next ? "set" : "null",
2033 pd->flags, pd->crc, pd->block);
2034 #endif
2035
2036
2037
2038
2039
2040 ret = rtems_fdisk_seg_write_page (fd, sc, page + sc->pages_desc, buffer);
2041 if (ret)
2042 {
2043 #if RTEMS_FDISK_TRACE
2044 rtems_fdisk_info (fd, "write-block:%02d-%03d-%03d: write page failed: " \
2045 "%s (%d)", sc->device, sc->segment, page,
2046 strerror (ret), ret);
2047 #endif
2048 }
2049 else
2050 {
2051 ret = rtems_fdisk_seg_write_page_desc (fd, sc, page, pd);
2052 if (ret)
2053 {
2054 #if RTEMS_FDISK_TRACE
2055 rtems_fdisk_info (fd, "write-block:%02d-%03d-%03d: " \
2056 "write page desc failed: %s (%d)",
2057 sc->device, sc->segment, bc->page,
2058 strerror (ret), ret);
2059 #endif
2060 }
2061 else
2062 {
2063 sc->pages_active++;
2064 }
2065 }
2066
2067 rtems_fdisk_queue_segment (fd, sc);
2068
2069 if (rtems_fdisk_is_erased_blocks_starvation (fd))
2070 rtems_fdisk_compact (fd);
2071
2072 return ret;
2073 }
2074 }
2075
2076 rtems_fdisk_error ("write-block: no erased page descs in segment: %d-%d",
2077 sc->device, sc->segment);
2078
2079 sc->failed = true;
2080 rtems_fdisk_queue_segment (fd, sc);
2081
2082 return EIO;
2083 }
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093 static int
2094 rtems_fdisk_read (rtems_flashdisk* fd, rtems_blkdev_request* req)
2095 {
2096 rtems_blkdev_sg_buffer* sg = req->bufs;
2097 uint32_t buf;
2098 int ret = 0;
2099
2100 for (buf = 0; (ret == 0) && (buf < req->bufnum); buf++, sg++)
2101 {
2102 uint8_t* data;
2103 uint32_t fb;
2104 uint32_t b;
2105 fb = sg->length / fd->block_size;
2106 data = sg->buffer;
2107 for (b = 0; b < fb; b++, data += fd->block_size)
2108 {
2109 ret = rtems_fdisk_read_block (fd, sg->block + b, data);
2110 if (ret)
2111 break;
2112 }
2113 }
2114
2115 rtems_blkdev_request_done (req, ret ? RTEMS_IO_ERROR : RTEMS_SUCCESSFUL);
2116
2117 return 0;
2118 }
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128 static int
2129 rtems_fdisk_write (rtems_flashdisk* fd, rtems_blkdev_request* req)
2130 {
2131 rtems_blkdev_sg_buffer* sg = req->bufs;
2132 uint32_t buf;
2133 int ret = 0;
2134
2135 for (buf = 0; (ret == 0) && (buf < req->bufnum); buf++, sg++)
2136 {
2137 uint8_t* data;
2138 uint32_t fb;
2139 uint32_t b;
2140 fb = sg->length / fd->block_size;
2141 data = sg->buffer;
2142 for (b = 0; b < fb; b++, data += fd->block_size)
2143 {
2144 ret = rtems_fdisk_write_block (fd, sg->block + b, data);
2145 if (ret)
2146 break;
2147 }
2148 }
2149
2150 rtems_blkdev_request_done (req, ret ? RTEMS_IO_ERROR : RTEMS_SUCCESSFUL);
2151
2152 return 0;
2153 }
2154
2155
2156
2157
2158
2159
2160
2161 static int
2162 rtems_fdisk_erase_disk (rtems_flashdisk* fd)
2163 {
2164 uint32_t device;
2165 int ret;
2166
2167 #if RTEMS_FDISK_TRACE
2168 rtems_fdisk_info (fd, "erase-disk");
2169 #endif
2170
2171 ret = rtems_fdisk_erase_flash (fd);
2172
2173 if (ret == 0)
2174 {
2175 for (device = 0; device < fd->device_count; device++)
2176 {
2177 if (!fd->devices[device].segments)
2178 return ENOMEM;
2179
2180 ret = rtems_fdisk_recover_block_mappings (fd);
2181 if (ret)
2182 break;
2183 }
2184 }
2185
2186 return ret;
2187 }
2188
2189
2190
2191
2192
2193 static int
2194 rtems_fdisk_monitoring_data (rtems_flashdisk* fd,
2195 rtems_fdisk_monitor_data* data)
2196 {
2197 uint32_t i;
2198 uint32_t j;
2199
2200 data->block_size = fd->block_size;
2201 data->block_count = fd->block_count;
2202 data->unavail_blocks = fd->unavail_blocks;
2203 data->device_count = fd->device_count;
2204
2205 data->blocks_used = 0;
2206 for (i = 0; i < fd->block_count; i++)
2207 if (fd->blocks[i].segment)
2208 data->blocks_used++;
2209
2210 data->segs_available = rtems_fdisk_segment_count_queue (&fd->available);
2211 data->segs_used = rtems_fdisk_segment_count_queue (&fd->used);
2212 data->segs_failed = rtems_fdisk_segment_count_queue (&fd->failed);
2213
2214 data->segment_count = 0;
2215 data->page_count = 0;
2216 data->pages_desc = 0;
2217 data->pages_active = 0;
2218 data->pages_used = 0;
2219 data->pages_bad = 0;
2220 data->seg_erases = 0;
2221
2222 for (i = 0; i < fd->device_count; i++)
2223 {
2224 data->segment_count += fd->devices[i].segment_count;
2225
2226 for (j = 0; j < fd->devices[i].segment_count; j++)
2227 {
2228 rtems_fdisk_segment_ctl* sc = &fd->devices[i].segments[j];
2229
2230 data->page_count += sc->pages;
2231 data->pages_desc += sc->pages_desc;
2232 data->pages_active += sc->pages_active;
2233 data->pages_used += sc->pages_used;
2234 data->pages_bad += sc->pages_bad;
2235 data->seg_erases += sc->erased;
2236 }
2237 }
2238
2239 data->info_level = fd->info_level;
2240 return 0;
2241 }
2242
2243
2244
2245
2246 static int
2247 rtems_fdisk_print_status (rtems_flashdisk* fd)
2248 {
2249 #if RTEMS_FDISK_TRACE
2250 uint32_t current_info_level = fd->info_level;
2251 uint32_t total;
2252 uint32_t count;
2253 uint32_t device;
2254
2255 fd->info_level = 3;
2256
2257 rtems_fdisk_printf (fd,
2258 "Flash Disk Driver Status : %d.%d", fd->major, fd->minor);
2259
2260 rtems_fdisk_printf (fd, "Block count\t%d", fd->block_count);
2261 rtems_fdisk_printf (fd, "Unavail blocks\t%d", fd->unavail_blocks);
2262 rtems_fdisk_printf (fd, "Starvation threshold\t%d", fd->starvation_threshold);
2263 rtems_fdisk_printf (fd, "Starvations\t%d", fd->starvations);
2264 count = rtems_fdisk_segment_count_queue (&fd->available);
2265 total = count;
2266 rtems_fdisk_printf (fd, "Available queue\t%ld (%ld)",
2267 count, rtems_fdisk_segment_queue_count (&fd->available));
2268 count = rtems_fdisk_segment_count_queue (&fd->used);
2269 total += count;
2270 rtems_fdisk_printf (fd, "Used queue\t%ld (%ld)",
2271 count, rtems_fdisk_segment_queue_count (&fd->used));
2272 count = rtems_fdisk_segment_count_queue (&fd->erase);
2273 total += count;
2274 rtems_fdisk_printf (fd, "Erase queue\t%ld (%ld)",
2275 count, rtems_fdisk_segment_queue_count (&fd->erase));
2276 count = rtems_fdisk_segment_count_queue (&fd->failed);
2277 total += count;
2278 rtems_fdisk_printf (fd, "Failed queue\t%ld (%ld)",
2279 count, rtems_fdisk_segment_queue_count (&fd->failed));
2280
2281 count = 0;
2282 for (device = 0; device < fd->device_count; device++)
2283 count += fd->devices[device].segment_count;
2284
2285 rtems_fdisk_printf (fd, "Queue total\t%ld of %ld, %s", total, count,
2286 total == count ? "ok" : "MISSING");
2287
2288 rtems_fdisk_printf (fd, "Device count\t%d", fd->device_count);
2289
2290 for (device = 0; device < fd->device_count; device++)
2291 {
2292 uint32_t block;
2293 uint32_t seg;
2294
2295 rtems_fdisk_printf (fd, " Device\t\t%ld", device);
2296 rtems_fdisk_printf (fd, " Segment count\t%ld",
2297 fd->devices[device].segment_count);
2298
2299 for (seg = 0; seg < fd->devices[device].segment_count; seg++)
2300 {
2301 rtems_fdisk_segment_ctl* sc = &fd->devices[device].segments[seg];
2302 uint32_t page;
2303 uint32_t erased = 0;
2304 uint32_t active = 0;
2305 uint32_t used = 0;
2306 bool is_active = false;
2307 char queues[5];
2308
2309 rtems_fdisk_queue_status (fd, sc, queues);
2310
2311 for (page = 0; page < sc->pages; page++)
2312 {
2313 if (rtems_fdisk_page_desc_erased (&sc->page_descriptors[page]))
2314 erased++;
2315 else if (rtems_fdisk_page_desc_flags_set (&sc->page_descriptors[page],
2316 RTEMS_FDISK_PAGE_ACTIVE))
2317 {
2318 if (rtems_fdisk_page_desc_flags_set (&sc->page_descriptors[page],
2319 RTEMS_FDISK_PAGE_USED))
2320 used++;
2321 else
2322 {
2323 active++;
2324 is_active = true;
2325 }
2326 }
2327
2328 for (block = 0; block < fd->block_count; block++)
2329 {
2330 if ((fd->blocks[block].segment == sc) &&
2331 (fd->blocks[block].page == page) && !is_active)
2332 rtems_fdisk_printf (fd,
2333 " %ld\t not active when mapped by block %ld",
2334 page, block);
2335 }
2336 }
2337
2338 count = 0;
2339 for (block = 0; block < fd->block_count; block++)
2340 {
2341 if (fd->blocks[block].segment == sc)
2342 count++;
2343 }
2344
2345 rtems_fdisk_printf (fd, " %3ld %s p:%3ld a:%3ld/%3ld" \
2346 " u:%3ld/%3ld e:%3ld/%3ld br:%ld",
2347 seg, queues,
2348 sc->pages, sc->pages_active, active,
2349 sc->pages_used, used, erased,
2350 sc->pages - (sc->pages_active +
2351 sc->pages_used + sc->pages_bad),
2352 count);
2353 }
2354 }
2355
2356 {
2357 rtems_fdisk_segment_ctl* sc = fd->used.head;
2358 int count = 0;
2359 rtems_fdisk_printf (fd, "Used List:");
2360 while (sc)
2361 {
2362 rtems_fdisk_printf (fd, " %3d %02d:%03d u:%3ld",
2363 count, sc->device, sc->segment, sc->pages_used);
2364 sc = sc->next;
2365 count++;
2366 }
2367 }
2368 fd->info_level = current_info_level;
2369
2370 return 0;
2371 #else
2372 return ENOSYS;
2373 #endif
2374 }
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384 static int
2385 rtems_fdisk_ioctl (rtems_disk_device *dd, uint32_t req, void* argp)
2386 {
2387 rtems_flashdisk* fd = rtems_disk_get_driver_data (dd);
2388 rtems_blkdev_request* r = argp;
2389
2390 errno = 0;
2391
2392 rtems_mutex_lock (&fd->lock);
2393
2394 switch (req)
2395 {
2396 case RTEMS_BLKIO_REQUEST:
2397 if (fd->device_count == 0)
2398 {
2399 errno = ENODEV;
2400 }
2401 else
2402 {
2403 switch (r->req)
2404 {
2405 case RTEMS_BLKDEV_REQ_READ:
2406 errno = rtems_fdisk_read (fd, r);
2407 break;
2408
2409 case RTEMS_BLKDEV_REQ_WRITE:
2410 errno = rtems_fdisk_write (fd, r);
2411 break;
2412
2413 default:
2414 errno = EINVAL;
2415 break;
2416 }
2417 }
2418 break;
2419
2420 case RTEMS_FDISK_IOCTL_ERASE_DISK:
2421 errno = rtems_fdisk_erase_disk (fd);
2422 break;
2423
2424 case RTEMS_FDISK_IOCTL_COMPACT:
2425 errno = rtems_fdisk_compact (fd);
2426 break;
2427
2428 case RTEMS_FDISK_IOCTL_ERASE_USED:
2429 errno = rtems_fdisk_erase_used (fd);
2430 break;
2431
2432 case RTEMS_FDISK_IOCTL_MONITORING:
2433 errno = rtems_fdisk_monitoring_data (fd,
2434 (rtems_fdisk_monitor_data*) argp);
2435 break;
2436
2437 case RTEMS_FDISK_IOCTL_INFO_LEVEL:
2438 fd->info_level = (uintptr_t) argp;
2439 break;
2440
2441 case RTEMS_FDISK_IOCTL_PRINT_STATUS:
2442 errno = rtems_fdisk_print_status (fd);
2443 break;
2444
2445 default:
2446 rtems_blkdev_ioctl (dd, req, argp);
2447 break;
2448 }
2449
2450 rtems_mutex_unlock (&fd->lock);
2451
2452 return errno == 0 ? 0 : -1;
2453 }
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464 rtems_device_driver
2465 rtems_fdisk_initialize (rtems_device_major_number major,
2466 rtems_device_minor_number minor,
2467 void* arg RTEMS_UNUSED)
2468 {
2469 const rtems_flashdisk_config* c = rtems_flashdisk_configuration;
2470 rtems_flashdisk* fd;
2471 rtems_status_code sc;
2472
2473 sc = rtems_fdisk_crc16_gen_factors (0x8408);
2474 if (sc != RTEMS_SUCCESSFUL)
2475 return sc;
2476
2477 fd = calloc (rtems_flashdisk_configuration_size, sizeof (*fd));
2478 if (!fd)
2479 return RTEMS_NO_MEMORY;
2480
2481 for (minor = 0; minor < rtems_flashdisk_configuration_size; minor++, c++, fd++)
2482 {
2483 char name[] = RTEMS_FLASHDISK_DEVICE_BASE_NAME "a";
2484 uint32_t device;
2485 uint32_t blocks = 0;
2486 int ret;
2487
2488 name [sizeof(RTEMS_FLASHDISK_DEVICE_BASE_NAME)] += minor;
2489
2490 fd->major = major;
2491 fd->minor = minor;
2492 fd->flags = c->flags;
2493 fd->compact_segs = c->compact_segs;
2494 fd->avail_compact_segs = c->avail_compact_segs;
2495 fd->block_size = c->block_size;
2496 fd->unavail_blocks = c->unavail_blocks;
2497 fd->info_level = c->info_level;
2498
2499 for (device = 0; device < c->device_count; device++)
2500 blocks += rtems_fdisk_blocks_in_device (&c->devices[device],
2501 c->block_size);
2502
2503
2504
2505
2506 fd->copy_buffer = malloc (c->block_size);
2507 if (!fd->copy_buffer)
2508 return RTEMS_NO_MEMORY;
2509
2510 fd->blocks = calloc (blocks, sizeof (rtems_fdisk_block_ctl));
2511 if (!fd->blocks)
2512 return RTEMS_NO_MEMORY;
2513
2514 fd->block_count = blocks;
2515
2516 fd->devices = calloc (c->device_count, sizeof (rtems_fdisk_device_ctl));
2517 if (!fd->devices)
2518 return RTEMS_NO_MEMORY;
2519
2520 rtems_mutex_init (&fd->lock, "Flash Disk");
2521
2522 sc = rtems_blkdev_create(name, c->block_size, blocks - fd->unavail_blocks,
2523 rtems_fdisk_ioctl, fd);
2524 if (sc != RTEMS_SUCCESSFUL)
2525 {
2526 rtems_mutex_destroy (&fd->lock);
2527 free (fd->copy_buffer);
2528 free (fd->blocks);
2529 free (fd->devices);
2530 rtems_fdisk_error ("disk create phy failed");
2531 return sc;
2532 }
2533
2534 for (device = 0; device < c->device_count; device++)
2535 {
2536 rtems_fdisk_segment_ctl* sc;
2537 uint32_t segment_count;
2538 uint32_t segment;
2539
2540 segment_count = rtems_fdisk_count_segments (&c->devices[device]);
2541
2542 fd->devices[device].segments = calloc (segment_count,
2543 sizeof (rtems_fdisk_segment_ctl));
2544 if (!fd->devices[device].segments)
2545 {
2546 unlink (name);
2547 rtems_mutex_destroy (&fd->lock);
2548 free (fd->copy_buffer);
2549 free (fd->blocks);
2550 free (fd->devices);
2551 return RTEMS_NO_MEMORY;
2552 }
2553
2554 sc = fd->devices[device].segments;
2555
2556 for (segment = 0; segment < c->devices[device].segment_count; segment++)
2557 {
2558 const rtems_fdisk_segment_desc* sd;
2559 uint32_t seg_segment;
2560
2561 sd = &c->devices[device].segments[segment];
2562
2563 for (seg_segment = 0; seg_segment < sd->count; seg_segment++, sc++)
2564 {
2565 sc->descriptor = sd;
2566 sc->device = device;
2567 sc->segment = seg_segment;
2568 sc->erased = 0;
2569 }
2570 }
2571
2572 fd->devices[device].segment_count = segment_count;
2573 fd->devices[device].descriptor = &c->devices[device];
2574 }
2575
2576 fd->device_count = c->device_count;
2577
2578 ret = rtems_fdisk_recover_block_mappings (fd);
2579 if (ret)
2580 {
2581 unlink (name);
2582 rtems_mutex_destroy (&fd->lock);
2583 free (fd->copy_buffer);
2584 free (fd->blocks);
2585 free (fd->devices);
2586 rtems_fdisk_error ("recovery of disk failed: %s (%d)",
2587 strerror (ret), ret);
2588 return ret;
2589 }
2590
2591 ret = rtems_fdisk_compact (fd);
2592 if (ret)
2593 {
2594 unlink (name);
2595 rtems_mutex_destroy (&fd->lock);
2596 free (fd->copy_buffer);
2597 free (fd->blocks);
2598 free (fd->devices);
2599 rtems_fdisk_error ("compacting of disk failed: %s (%d)",
2600 strerror (ret), ret);
2601 return ret;
2602 }
2603 }
2604
2605 return RTEMS_SUCCESSFUL;
2606 }