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 #ifdef HAVE_CONFIG_H
0037 #include "config.h"
0038 #endif
0039
0040 #include <rtems.h>
0041 #include <rtems/libio.h>
0042 #include <errno.h>
0043 #include <stdlib.h>
0044 #include <stdio.h>
0045 #include <string.h>
0046 #include <inttypes.h>
0047
0048 #include <rtems/blkdev.h>
0049 #include <rtems/nvdisk.h>
0050 #include <rtems/thread.h>
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076 #if !defined (RTEMS_NVDISK_TRACE)
0077 #define RTEMS_NVDISK_TRACE 0
0078 #endif
0079
0080
0081
0082
0083 typedef struct rtems_nvdisk_device_ctl
0084 {
0085
0086
0087
0088 uint32_t device;
0089
0090
0091
0092
0093 uint32_t pages;
0094
0095
0096
0097
0098 uint32_t pages_desc;
0099
0100
0101
0102
0103 uint32_t block_base;
0104
0105
0106
0107
0108 const rtems_nvdisk_device_desc* descriptor;
0109 } rtems_nvdisk_device_ctl;
0110
0111
0112
0113
0114
0115 typedef struct
0116 {
0117 uint32_t flags;
0118 uint32_t block_size;
0119 uint32_t block_count;
0120 rtems_nvdisk_device_ctl* devices;
0121 uint32_t device_count;
0122 uint32_t cs_pages;
0123 rtems_mutex lock;
0124 uint32_t info_level;
0125 } rtems_nvdisk;
0126
0127
0128
0129
0130 static uint16_t* rtems_nvdisk_crc16_factor;
0131
0132
0133
0134
0135
0136
0137
0138 #define rtems_nvdisk_calc_crc16(_b, _c) \
0139 rtems_nvdisk_crc16_factor[((_b) ^ ((_c) & 0xff)) & 0xff] ^ (((_c) >> 8) & 0xff)
0140
0141
0142
0143
0144
0145
0146
0147
0148 static rtems_status_code
0149 rtems_nvdisk_crc16_gen_factors (uint16_t pattern)
0150 {
0151 uint32_t b;
0152
0153 rtems_nvdisk_crc16_factor = malloc (sizeof (uint16_t) * 256);
0154 if (!rtems_nvdisk_crc16_factor)
0155 return RTEMS_NO_MEMORY;
0156
0157 for (b = 0; b < 256; b++)
0158 {
0159 uint32_t i;
0160 uint16_t v = b;
0161 for (i = 8; i--;)
0162 v = v & 1 ? (v >> 1) ^ pattern : v >> 1;
0163 rtems_nvdisk_crc16_factor[b] = v & 0xffff;
0164 }
0165 return RTEMS_SUCCESSFUL;
0166 }
0167
0168 #if RTEMS_NVDISK_TRACE
0169
0170
0171
0172
0173
0174
0175
0176
0177 static int
0178 rtems_nvdisk_printf (const rtems_nvdisk* nvd, const char *format, ...)
0179 {
0180 int ret = 0;
0181 if (nvd->info_level >= 3)
0182 {
0183 va_list args;
0184 va_start (args, format);
0185 fprintf (stdout, "nvdisk:");
0186 ret = vfprintf (stdout, format, args);
0187 fprintf (stdout, "\n");
0188 fflush (stdout);
0189 va_end (args);
0190 }
0191 return ret;
0192 }
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202 static int
0203 rtems_nvdisk_info (const rtems_nvdisk* nvd, const char *format, ...)
0204 {
0205 int ret = 0;
0206 if (nvd->info_level >= 2)
0207 {
0208 va_list args;
0209 va_start (args, format);
0210 fprintf (stdout, "nvdisk:");
0211 ret = vfprintf (stdout, format, args);
0212 fprintf (stdout, "\n");
0213 fflush (stdout);
0214 va_end (args);
0215 }
0216 return ret;
0217 }
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227 static int
0228 rtems_nvdisk_warning (const rtems_nvdisk* nvd, const char *format, ...)
0229 {
0230 int ret = 0;
0231 if (nvd->info_level >= 1)
0232 {
0233 va_list args;
0234 va_start (args, format);
0235 fprintf (stdout, "nvdisk:warning:");
0236 ret = vfprintf (stdout, format, args);
0237 fprintf (stdout, "\n");
0238 fflush (stdout);
0239 va_end (args);
0240 }
0241 return ret;
0242 }
0243 #endif
0244
0245
0246
0247
0248
0249
0250
0251
0252 static int
0253 rtems_nvdisk_error (const char *format, ...)
0254 {
0255 int ret;
0256 va_list args;
0257 va_start (args, format);
0258 fprintf (stderr, "nvdisk:error:");
0259 ret = vfprintf (stderr, format, args);
0260 fprintf (stderr, "\n");
0261 fflush (stderr);
0262 va_end (args);
0263 return ret;
0264 }
0265
0266
0267
0268
0269 static const rtems_nvdisk_device_desc*
0270 rtems_nvdisk_device_descriptor (const rtems_nvdisk* nvd, uint32_t device)
0271 {
0272 return nvd->devices[device].descriptor;
0273 }
0274
0275
0276
0277
0278 static int
0279 rtems_nvdisk_device_read (const rtems_nvdisk* nvd,
0280 uint32_t device,
0281 uint32_t offset,
0282 void* buffer,
0283 uint32_t size)
0284 {
0285 const rtems_nvdisk_device_desc* dd;
0286 const rtems_nvdisk_driver_handlers* ops;
0287 dd = rtems_nvdisk_device_descriptor (nvd, device);
0288 ops = nvd->devices[device].descriptor->nv_ops;
0289 #if RTEMS_NVDISK_TRACE
0290 rtems_nvdisk_printf (nvd, " dev-read: %02d-%08x: s=%d",
0291 device, offset, size);
0292 #endif
0293 return ops->read (device, dd->flags, dd->base, offset, buffer, size);
0294 }
0295
0296
0297
0298
0299 static int
0300 rtems_nvdisk_device_write (const rtems_nvdisk* nvd,
0301 uint32_t device,
0302 uint32_t offset,
0303 const void* buffer,
0304 uint32_t size)
0305 {
0306 const rtems_nvdisk_device_desc* dd;
0307 const rtems_nvdisk_driver_handlers* ops;
0308 dd = rtems_nvdisk_device_descriptor (nvd, device);
0309 ops = nvd->devices[device].descriptor->nv_ops;
0310 #if RTEMS_NVDISK_TRACE
0311 rtems_nvdisk_printf (nvd, " dev-write: %02d-%08x: s=%d",
0312 device, offset, size);
0313 #endif
0314 return ops->write (device, dd->flags, dd->base, offset, buffer, size);
0315 }
0316
0317 #if NOT_USED
0318
0319
0320
0321 static int
0322 rtems_nvdisk_device_verify (const rtems_nvdisk* nvd,
0323 uint32_t device,
0324 uint32_t offset,
0325 const void* buffer,
0326 uint32_t size)
0327 {
0328 const rtems_nvdisk_device_desc* dd;
0329 const rtems_nvdisk_driver_handlers* ops;
0330 dd = rtems_nvdisk_device_descriptor (nvd, device);
0331 ops = nvd->devices[device].descriptor->nv_ops;
0332 #if RTEMS_NVDISK_TRACE
0333 rtems_nvdisk_printf (nvd, " seg-verify: %02d-%08x: s=%d",
0334 device, offset, size);
0335 #endif
0336 return ops->verify (device, dd->flags, dd->base, offset, buffer, size);
0337 }
0338 #endif
0339
0340
0341
0342
0343 static int
0344 rtems_nvdisk_read_page (const rtems_nvdisk* nvd,
0345 uint32_t device,
0346 uint32_t page,
0347 void* buffer)
0348 {
0349 return rtems_nvdisk_device_read (nvd, device,
0350 page * nvd->block_size, buffer,
0351 nvd->block_size);
0352 }
0353
0354
0355
0356
0357 static int
0358 rtems_nvdisk_write_page (const rtems_nvdisk* nvd,
0359 uint32_t device,
0360 uint32_t page,
0361 const void* buffer)
0362 {
0363 return rtems_nvdisk_device_write (nvd, device,
0364 page * nvd->block_size,
0365 buffer, nvd->block_size);
0366 }
0367
0368
0369
0370
0371 static int
0372 rtems_nvdisk_read_checksum (const rtems_nvdisk* nvd,
0373 uint32_t device,
0374 uint32_t page,
0375 uint16_t* cs)
0376 {
0377 return rtems_nvdisk_device_read (nvd, device,
0378 page * sizeof (uint16_t),
0379 cs, sizeof (uint16_t));
0380 }
0381
0382
0383
0384
0385 static int
0386 rtems_nvdisk_write_checksum (const rtems_nvdisk* nvd,
0387 uint32_t device,
0388 uint32_t page,
0389 const uint16_t cs)
0390 {
0391 return rtems_nvdisk_device_write (nvd, device,
0392 page * sizeof (uint16_t),
0393 &cs, sizeof (uint16_t));
0394 }
0395
0396
0397
0398
0399
0400
0401
0402
0403 static uint32_t
0404 rtems_nvdisk_pages_in_device (const rtems_nvdisk* nvd,
0405 const rtems_nvdisk_device_desc* dd)
0406 {
0407 return dd->size / nvd->block_size;
0408 }
0409
0410
0411
0412
0413
0414 static uint32_t
0415 rtems_nvdisk_page_desc_pages (const rtems_nvdisk* nvd,
0416 const rtems_nvdisk_device_desc* dd)
0417 {
0418 uint32_t pages = rtems_nvdisk_pages_in_device (nvd, dd);
0419 uint32_t bytes = pages * sizeof (uint16_t);
0420 return ((bytes - 1) / nvd->block_size) + 1;
0421 }
0422
0423
0424
0425
0426 static uint16_t
0427 rtems_nvdisk_page_checksum (const uint8_t* buffer, uint32_t page_size)
0428 {
0429 uint16_t cs = 0xffff;
0430 uint32_t i;
0431
0432 for (i = 0; i < page_size; i++, buffer++)
0433 cs = rtems_nvdisk_calc_crc16 (*buffer, cs);
0434
0435 return cs;
0436 }
0437
0438
0439
0440
0441 static rtems_nvdisk_device_ctl*
0442 rtems_nvdisk_get_device (rtems_nvdisk* nvd, uint32_t block)
0443 {
0444 uint32_t device;
0445
0446 if (block >= nvd->block_count)
0447 {
0448 rtems_nvdisk_error ("read-block: bad block: %d", block);
0449 return NULL;
0450 }
0451
0452 for (device = 0; device < nvd->device_count; device++)
0453 {
0454 rtems_nvdisk_device_ctl* dc = &nvd->devices[device];
0455 if ((block >= dc->block_base) &&
0456 (block < (dc->block_base + dc->pages - dc->pages_desc)))
0457 return dc;
0458 }
0459
0460 rtems_nvdisk_error ("map-block:%d: no device/page map found", block);
0461
0462 return NULL;
0463 }
0464
0465
0466
0467
0468 static uint32_t
0469 rtems_nvdisk_get_page (rtems_nvdisk_device_ctl* dc,
0470 uint32_t block)
0471 {
0472 return block - dc->block_base;
0473 }
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485 static int
0486 rtems_nvdisk_read_block (rtems_nvdisk* nvd, uint32_t block, uint8_t* buffer)
0487 {
0488 rtems_nvdisk_device_ctl* dc;
0489 uint32_t page;
0490 uint16_t crc;
0491 uint16_t cs;
0492 int ret;
0493
0494 dc = rtems_nvdisk_get_device (nvd, block);
0495
0496 if (!dc)
0497 return EIO;
0498
0499 page = rtems_nvdisk_get_page (dc, block);
0500
0501 #if RTEMS_NVDISK_TRACE
0502 rtems_nvdisk_info (nvd, " read-block:%d=>%02d-%03d, cs:%04x",
0503 block, dc->device, page, crc);
0504 #endif
0505
0506 ret = rtems_nvdisk_read_checksum (nvd, dc->device, page, &crc);
0507
0508 if (ret)
0509 return ret;
0510
0511 if (crc == 0xffff)
0512 {
0513 #if RTEMS_NVDISK_TRACE
0514 rtems_nvdisk_warning (nvd, "read-block: crc not set: %d", block);
0515 #endif
0516 memset (buffer, 0, nvd->block_size);
0517 return 0;
0518 }
0519
0520 ret = rtems_nvdisk_read_page (nvd, dc->device, page + dc->pages_desc, buffer);
0521
0522 if (ret)
0523 return ret;
0524
0525 cs = rtems_nvdisk_page_checksum (buffer, nvd->block_size);
0526
0527 if (cs != crc)
0528 {
0529 rtems_nvdisk_error ("read-block: crc failure: %d: buffer:%04x page:%04x",
0530 block, cs, crc);
0531 return EIO;
0532 }
0533
0534 return 0;
0535 }
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548 static int
0549 rtems_nvdisk_write_block (rtems_nvdisk* nvd,
0550 uint32_t block,
0551 const unsigned char* buffer)
0552 {
0553 rtems_nvdisk_device_ctl* dc;
0554 uint32_t page;
0555 uint16_t cs;
0556 int ret;
0557
0558 dc = rtems_nvdisk_get_device (nvd, block);
0559
0560 if (!dc)
0561 return EIO;
0562
0563 page = rtems_nvdisk_get_page (dc, block);
0564
0565 cs = rtems_nvdisk_page_checksum (buffer, nvd->block_size);
0566
0567 #if RTEMS_NVDISK_TRACE
0568 rtems_nvdisk_info (nvd, " write-block:%d=>%02d-%03d", block, dc->device, page);
0569 #endif
0570
0571 ret = rtems_nvdisk_write_page (nvd, dc->device, page + dc->pages_desc, buffer);
0572
0573 if (ret)
0574 return ret;
0575
0576 return rtems_nvdisk_write_checksum (nvd, dc->device, page, cs);
0577 }
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587 static int
0588 rtems_nvdisk_read (rtems_nvdisk* nvd, rtems_blkdev_request* req)
0589 {
0590 rtems_blkdev_sg_buffer* sg = req->bufs;
0591 uint32_t bufs;
0592 int ret = 0;
0593
0594 #if RTEMS_NVDISK_TRACE
0595 rtems_nvdisk_info (nvd, "read: blocks=%d", req->bufnum);
0596 #endif
0597
0598 for (bufs = 0; (ret == 0) && (bufs < req->bufnum); bufs++, sg++)
0599 {
0600 uint8_t* data;
0601 uint32_t nvb;
0602 uint32_t b;
0603 nvb = sg->length / nvd->block_size;
0604 data = sg->buffer;
0605 for (b = 0; b < nvb; b++, data += nvd->block_size)
0606 {
0607 ret = rtems_nvdisk_read_block (nvd, sg->block + b, data);
0608 if (ret)
0609 break;
0610 }
0611 }
0612
0613 rtems_blkdev_request_done (req, ret ? RTEMS_IO_ERROR : RTEMS_SUCCESSFUL);
0614
0615 return 0;
0616 }
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626 static int
0627 rtems_nvdisk_write (rtems_nvdisk* nvd, rtems_blkdev_request* req)
0628 {
0629 rtems_blkdev_sg_buffer* sg = req->bufs;
0630 uint32_t bufs;
0631 int ret = 0;
0632
0633 #if RTEMS_NVDISK_TRACE
0634 rtems_nvdisk_info (nvd, "write: blocks=%d", req->bufnum);
0635 #endif
0636
0637 for (bufs = 0; (ret == 0) && (bufs < req->bufnum); bufs++, sg++)
0638 {
0639 uint8_t* data;
0640 uint32_t nvb;
0641 uint32_t b;
0642 nvb = sg->length / nvd->block_size;
0643 data = sg->buffer;
0644 for (b = 0; b < nvb; b++, data += nvd->block_size)
0645 {
0646 ret = rtems_nvdisk_write_block (nvd, sg->block + b, data);
0647 if (ret)
0648 break;
0649 }
0650 }
0651
0652 rtems_blkdev_request_done (req, ret ? RTEMS_IO_ERROR : RTEMS_SUCCESSFUL);
0653
0654 return 0;
0655 }
0656
0657
0658
0659
0660
0661
0662
0663 static int
0664 rtems_nvdisk_erase_disk (rtems_nvdisk* nvd)
0665 {
0666 uint32_t device;
0667
0668 #if RTEMS_NVDISK_TRACE
0669 rtems_nvdisk_info (nvd, "erase-disk");
0670 #endif
0671
0672 for (device = 0; device < nvd->device_count; device++)
0673 {
0674 rtems_nvdisk_device_ctl* dc = &nvd->devices[device];
0675 uint32_t page;
0676 for (page = 0; page < (dc->pages - dc->pages_desc); page++)
0677 {
0678 int ret = rtems_nvdisk_write_checksum (nvd, dc->device, page, 0xffff);
0679 if (ret)
0680 return ret;
0681 }
0682 }
0683
0684 return 0;
0685 }
0686
0687
0688
0689
0690
0691
0692
0693
0694
0695 static int
0696 rtems_nvdisk_ioctl (rtems_disk_device *dd, uint32_t req, void* argp)
0697 {
0698 rtems_nvdisk* nvd = rtems_disk_get_driver_data (dd);
0699 rtems_blkdev_request* r = argp;
0700
0701 if (nvd->device_count == 0)
0702 {
0703 errno = ENODEV;
0704 return -1;
0705 }
0706
0707 errno = 0;
0708
0709 rtems_mutex_lock (&nvd->lock);
0710
0711 switch (req)
0712 {
0713 case RTEMS_BLKIO_REQUEST:
0714 switch (r->req)
0715 {
0716 case RTEMS_BLKDEV_REQ_READ:
0717 errno = rtems_nvdisk_read (nvd, r);
0718 break;
0719
0720 case RTEMS_BLKDEV_REQ_WRITE:
0721 errno = rtems_nvdisk_write (nvd, r);
0722 break;
0723
0724 default:
0725 errno = EINVAL;
0726 break;
0727 }
0728 break;
0729
0730 case RTEMS_NVDISK_IOCTL_ERASE_DISK:
0731 errno = rtems_nvdisk_erase_disk (nvd);
0732 break;
0733
0734 case RTEMS_NVDISK_IOCTL_INFO_LEVEL:
0735 nvd->info_level = (uintptr_t) argp;
0736 break;
0737
0738 default:
0739 rtems_blkdev_ioctl (dd, req, argp);
0740 break;
0741 }
0742
0743 rtems_mutex_unlock (&nvd->lock);
0744
0745 return errno == 0 ? 0 : -1;
0746 }
0747
0748
0749
0750
0751
0752
0753
0754
0755
0756
0757 rtems_device_driver
0758 rtems_nvdisk_initialize (rtems_device_major_number major RTEMS_UNUSED,
0759 rtems_device_minor_number minor RTEMS_UNUSED,
0760 void* arg RTEMS_UNUSED)
0761 {
0762 const rtems_nvdisk_config* c = rtems_nvdisk_configuration;
0763 rtems_nvdisk* nvd;
0764 rtems_status_code sc;
0765 uint32_t i;
0766
0767 sc = rtems_nvdisk_crc16_gen_factors (0x8408);
0768 if (sc != RTEMS_SUCCESSFUL)
0769 return sc;
0770
0771 nvd = calloc (rtems_nvdisk_configuration_size, sizeof (*nvd));
0772 if (!nvd)
0773 return RTEMS_NO_MEMORY;
0774
0775 for (i = 0; i < rtems_nvdisk_configuration_size; i++, c++, nvd++)
0776 {
0777 char name[] = RTEMS_NVDISK_DEVICE_BASE_NAME "a";
0778 uint32_t device;
0779 uint32_t blocks = 0;
0780
0781 name [sizeof(RTEMS_NVDISK_DEVICE_BASE_NAME)] += i;
0782
0783 nvd->flags = c->flags;
0784 nvd->block_size = c->block_size;
0785 nvd->info_level = c->info_level;
0786
0787 nvd->devices = calloc (c->device_count, sizeof (rtems_nvdisk_device_ctl));
0788 if (!nvd->devices)
0789 return RTEMS_NO_MEMORY;
0790
0791 for (device = 0; device < c->device_count; device++)
0792 {
0793 rtems_nvdisk_device_ctl* dc = &nvd->devices[device];
0794
0795 dc->device = device;
0796 dc->pages = rtems_nvdisk_pages_in_device (nvd, &c->devices[device]);
0797 dc->pages_desc = rtems_nvdisk_page_desc_pages (nvd, &c->devices[device]);
0798 dc->block_base = blocks;
0799
0800 blocks += dc->pages - dc->pages_desc;
0801
0802 dc->descriptor = &c->devices[device];
0803 }
0804
0805 nvd->block_count = blocks;
0806 nvd->device_count = c->device_count;
0807
0808 sc = rtems_blkdev_create(name, c->block_size, blocks,
0809 rtems_nvdisk_ioctl, nvd);
0810 if (sc != RTEMS_SUCCESSFUL)
0811 {
0812 rtems_nvdisk_error ("disk create phy failed");
0813 return sc;
0814 }
0815
0816 rtems_mutex_init (&nvd->lock, "NV Disk");
0817 }
0818
0819 return RTEMS_SUCCESSFUL;
0820 }