summaryrefslogtreecommitdiffstats
path: root/src/usr/isteps/nvdimm/bpm_update.H
blob: 4886a8abdce2e3d490988f4e77cbda589afd1487 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/isteps/nvdimm/bpm_update.H $                          */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2019                             */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

#ifndef BPM_UPDATE_H
#define BPM_UPDATE_H

/* @file bpm_update.H
 *
 *
 */

#include <vector>
#include <errl/errlentry.H>
#include <targeting/common/util.H>

namespace NVDIMM
{
namespace BPM
{

/*
 * All of the various commands used for the BPM update. All commands can only be
 * sent after write protection on the BPM has been disabled and the update magic
 * values have been written to the BPM's magic registers.
 *
 * BSL: Bootstrap Loader commands
 * BPM: Backup Power Module
*/
enum COMMAND : uint8_t
{
    // A payload sent with this command will be interpreted and processed by the
    // NVDIMM module.
    BPM_LOCAL                 = 0xFF,

    /*
     * These are LOCAL commands. These commands MUST be sent only outside of BSL
     * BSL mode and must be paired with the BSP command BPM_LOCAL. Otherwise,
     * unpredicatable errors will occur.
     *
     * When using issueCommand() for these commands they should always be sent
     * with a 0 ms delay. This will ensure that the response packet is not
     * checked from the BPM. Since these are processed by the NVDIMM it makes
     * no sense to get a response from the BPM and attempting to do so will
     * cause errors.
     */
    BCL_ENTER_BSL_MODE        = 0x01,
    BCL_IS_BSL_MODE           = 0x02,
    BCL_WRITE_REG             = 0x03,
    BCL_START_UPDATE          = 0x04,
    BCL_END_UPDATE            = 0x05,
    BCL_IS_UPDATE_IN_PROGRESS = 0x06,

    // A payload sent with this command will be sent transparently to the BPM.
    // This command must only be used while the BPM is in BSL mode.
    BPM_PASSTHROUGH           = 0xFE,

    /*
     * These are PASSTHROUGH commands. These commands MUST be sent only while in
     * BSL mode and must be paired with BSP command BPM_PASSTHROUGH. Otherwise,
     * unpredicatable errors will occur.
     */
    // Writes a block of data to the BPM.
    // Delay 1ms (default)
    BSL_RX_DATA_BLOCK         = 0x10,
    // Unlocks the BPM that is in BSL mode so that updates can occur.
    // Delay 1ms (default)
    BSL_RX_PASSWORD           = 0x11,
    // Erases 128 bytes at the given address offset.
    // WARNING: Due to BSL memory limitations, BSL cannot verify the address
    //          is a valid config segment address offset and will blindly
    //          erase 128 bytes of data starting at that offset. If an invalid
    //          address is sent then the BPM will be bricked in a very
    //          unpredicatable/unrecoverable way.
    // Delay 250ms
    BSL_ERASE_SEGMENT         = 0x12,
    // Unknown, unused.
    // Delay 0ms
    BSL_TOGGLE_INFO           = 0x13,
    // Unknown, unused.
    // Delay 1ms (default)
    BSL_ERASE_BLOCK           = 0x14,
    // Erases the full firmware section on the BPM. The start of the firmware
    // address must be supplied with this command.
    // WARNING: Due to BSL memory limitations, BSL cannot verify the address
    //          is a valid firmware address offset and will blindly erase 128
    //          data starting at that offset. If an invalid address is sent
    //          then the BPM will be bricked in a very
    //          unpredicatable/unrecoverable way.
    // Delay 250ms
    BSL_MASS_ERASE            = 0x15,
    // Sends the command to the BPM to perform the final CRC check on the
    // firmware written to the BPM. If the CRC check doesn't match the expected
    // CRC in the flash image then the firmware will not load on the BPM and it
    // will remain in BSL mode until new firmware is loaded onto it.
    //
    // Delay 0
    // The response packet must be checked externally from the issueCommand()
    // function because the response packet returned from this command is unique
    // to this command and will return the results of this command. For more
    // info see the checkFirmwareCrc() function description, implementation, and
    // the COMMAND_BSL_CRC_CHECK_RESPONSE_CODES enum.
    BSL_CRC_CHECK             = 0x16,
    // Unknown, unused.
    // Delay 1ms (default)
    BSL_LOAD_PC               = 0x17,
    // Unknown, unused.
    // Delay 1ms (default)
    BSL_TX_DATA_BLOCK         = 0x18,
    // Checks the Bootstrap Loader mode version on the BPM. Depending on this
    // version, some parts of the update procedure may have changed.
    //
    // Delay 0ms
    // The response packet must be checked externally from the issueCommand()
    // function because the response packet returned from this command is unique
    // to this command and will return the results of this command. For more
    // info see the readBslVersion() function description and implementation.
    BSL_TX_BSL_VERSION        = 0x19,
    // Unknown, unused.
    // Delay 1ms (default)
    BSL_TX_BUFFER_SIZE        = 0x1A,
    // Unknown, unused.
    // Delay 1ms (default)
    BSL_RX_DATA_BLOCK_FAST    = 0x1B,
    // Resets the BPM and exits BSL mode.
    // Delay 0ms
    // Never check for a response packet from the BPM after sending the reset
    // command because the BPM may not be back up and if it is it will not be
    // in BSL mode anymore. If the response packet is checked then errors will
    // occur.
    BSL_RESET_DEVICE          = 0x1C,
    // Verifies the block of data written to the BPM flash is identical to what
    // was sent to it in a prior write. For more information see the
    // verifyBlockWrite() description and implementation.
    //
    // Delay 0ms
    // The response packet must be checked externally from the issueCommand()
    // function because the response packet returned from this command is unique
    // to this command and will return the results of this command.
    BSL_VERIFY_BLOCK          = 0x1D,
};

// These consts serve as reminders in the code for what was explained in the
// COMMAND enum.
const int NO_DELAY_NO_RESPONSE       = 0;
const int NO_DELAY_EXTERNAL_RESPONSE = 0;
const int ERASE_SEGMENT_DELAY        = 250;
const int ERASE_FIRMWARE_DELAY       = 250;

// These are the various response codes returned by the BPM after the
// BSL_CRC_CHECK command is sent at the end of the update procedure.
enum COMMAND_BSL_CRC_CHECK_RESPONSE_CODES : uint16_t
{
    // The updated firmware is set up with all necessary loading parameters to
    // load and execute upon reset.
    SUCCESSFUL_OPERATION          = 0x00,

    // Error setting up the necessary loading parameters for the updated
    // firmware image.
    MEMORY_WRITE_CHECK_FAILED     = 0x01,

    // The command was attempted without unlocking the BSL with the password.
    BSL_LOCKED                    = 0x04,

    // Error setting up the necessary loading parameters for the updated
    // firmware image.
    WRITE_FORBIDDEN               = 0x06,

    // The checksum validation of the updated firmware image failed. The
    // calculated checksum doesn't match the checksum data provided @FF7A in the
    // firmware image file.
    VERIFY_MISMATCH               = 0x09,

    // The firmware image start address given for the command is wrong.
    PARAMETER_ERROR               = 0x0A,

    // Firmware image file used for the update doesn't hae the checksum data
    // defined @FF7A
    MAIN_FW_NOT_SUPPORT_CRC_CHECK = 0x0B,
};

//  BSL versions that this code supports.
const uint8_t BSL_VERSION_1_4 = 0x14;

// The operator types for the BPM_CMD_STATUS register
enum COMMAND_STATUS_REGISTER_OP_TYPES : uint8_t
{
    NOP        = 0x00,
    READ       = 0x01,
    WRITE      = 0x02,
    NO_TRASFER = 0x03,
};

// Used to overlay onto the LID image
struct firmware_image_block
{
    // The block size is the sizeof(iv_addressOffset) plus sizeof(iv_data).
    uint8_t iv_blockSize;

    // The address offset where the first byte in iv_data came from in the
    // firmware image.
    uint16_t iv_addressOffset;

    // A variable sized array of firmware data. The size of which is always
    // iv_blockSize - sizeof(iv_addressOffset) and the max this can be is
    // MAX_PAYLOAD_SIZE.
    char iv_data[0];

} PACKED;

typedef firmware_image_block firmware_image_block_t;


// Used to overlay onto the LID image
struct config_image_fragment
{
    // The fragment size is the size of iv_data.
    uint8_t iv_fragmentSize;

    // The offset where the first byte in iv_data should begin overwritting the
    // BPM config data in the BPM configuration segment dump buffer.
    uint16_t iv_offset;

    // A variable sized array of config segment data.
    char iv_data[0];

} PACKED;

typedef config_image_fragment config_image_fragment_t;


/*    Max payload size is 26 bytes
 *    4 bytes: header
 *        1 byte: sync byte
 *        1 byte: command
 *        1 byte: header size + data size
 *        1 byte: header size + data size
 *    2 bytes: address
 *    2 bytes: extra
 *    16 bytes: data
 *    2 bytes: CRC
 */
constexpr size_t MAX_PAYLOAD_SIZE = 26;

// Max number of bytes data section of payload can be.
constexpr size_t MAX_PAYLOAD_DATA_SIZE = 16;

// Number of bytes for header, address, extra, and CRC
constexpr size_t MAX_PAYLOAD_OTHER_DATA_SIZE = 10;

// Number of bytes for the header.
constexpr uint8_t PAYLOAD_HEADER_SIZE = 4;

// Indices of where to find certain data within a constructed payload.
// These indices have been subtracted by 1 from the given payload format because
// after a payload is constructed the sync byte is removed from the front.
constexpr uint8_t PAYLOAD_COMMAND_INDEX = 0;
constexpr uint8_t PAYLOAD_ADDRESS_START_INDEX = 3;
constexpr uint8_t PAYLOAD_DATA_START_INDEX = 7;
constexpr uint8_t PAYLOAD_HEADER_DATA_LENGTH_INDEX = 1;

// The sync byte that must always be at the front of a BPM payload. This is used
// calculate the CRC of the payload and then removed because the nvdimm
// automatically sends the sync byte ahead of the payload.
constexpr uint8_t SYNC_BYTE = 0x80;
constexpr uint8_t SYNC_BYTE_SIZE = sizeof(uint8_t);

// Maximum size of any segment in the config data section
constexpr size_t SEGMENT_SIZE = 128;

// Maximum size of the config data section.
constexpr size_t ALL_SEGMENTS_SIZE = 512;

// Number of magic registers for the BPM
constexpr size_t NUM_MAGIC_REGISTERS = 2;

// These are the production magic values for the BPM that should be written in
// BPM_MAGIC_REG1 and BPM_MAGIC_REG2 respectively.
const uint8_t PRODUCTION_MAGIC_VALUES[NUM_MAGIC_REGISTERS] = {0x55, 0xAA};
// These magic values to enable nvdimm-bpm interface. They must be written to
// the magic registers BEFORE writing flash updates to the BPM in BSL mode.
const uint8_t UPDATE_MODE_MAGIC_VALUES[NUM_MAGIC_REGISTERS] = {0xB0, 0xDA};
// These are the segment read magic values that allow dumping of the segment
// data from the BPM.
const uint8_t SEGMENT_READ_MAGIC_VALUES[NUM_MAGIC_REGISTERS] = {0xBA, 0xAB};

typedef std::vector<uint8_t> payload_t;


/**
 *  @brief BPM_CMD_STATUS register bits
 */
struct command_status_register_bits
{
    uint8_t Abort_Request       : 1; // Bit 7
    uint8_t Abort_Acknowledge   : 1; // Bit 6
    uint8_t Reserved1           : 1; // Bit 5
    uint8_t Reserved2           : 1; // Bit 4
    uint8_t Error_Flag          : 1; // Bit 3
    uint8_t Bsp_Cmd_In_Progress : 1; // Bit 2
    uint8_t Operator_Type       : 2; // Bit 1-0
} PACKED;

/**
 *  @brief Union simplifying manipulation of REG_CMD_STATUS value
 */
union command_status_register_union
{
    uint8_t value;
    command_status_register_bits bits;

    /**
     *  @brief Constructor
     */
    command_status_register_union()
    : value(0)
    {}

} PACKED;

typedef command_status_register_union command_status_register_t;

class BpmFirmwareLidImage
{
public:

    /**
    * @brief Constructor that sets access to LID information
    *
    * @param[in] i_lidImageAddr  virtual address where LID was loaded
    * @param[in] i_size          size of the loaded LID
    */
    BpmFirmwareLidImage(void * const i_lidImageAddr, size_t i_size);

    /**
    * @brief Returns the version of the firmware binary as a uint16_t
    *
    * @return uint16_t   version of the firmware image as MMmm.
    *                    MM = major version, mm = minor.
    */
    uint16_t getVersion() const;

    /**
    * @brief Returns the number of blocks in the LID image.
    *
    */
    uint16_t getNumberOfBlocks() const;

    /**
     * @brief Returns a pointer to the first block in LID image.
     */
    void const * getFirstBlock() const;

    /* Layout of the BPM Firmware image
    *  Byte 1:     Major version number (MM)
    *  Byte 2:     Minor version number (mm)
    *  Byte 3-4:   N number of blocks in the file (NN NN)
    *  Byte 5-EOF: Blocks of the form:
    *            BLOCK_SIZE      Byte 1: X number of bytes in block excluding
    *                                    this byte. (XX)
    *            ADDRESS_OFFSET  Byte 2-3: Original address offset of the
    *                                      first data byte. (AD DR)
    *            DATA_BYTES      Byte 4-X: Firmware data bytes (DD)
    *
    *  Example file:
    *     01 03 00 01 06 80 00 6a 14 31 80
    *     MM mm NN NN XX AD DR DD DD DD DD
    */
    typedef struct firmware_image_header
    {
        uint8_t iv_versionMajor;
        uint8_t iv_versionMinor;
        uint16_t iv_numberOfBlocks;
    } firmware_image_header_t;

private:

    // Pointer to the LID image allocated outside of the class
    void * const iv_lidImage;

    // The size of the LID image.
    size_t iv_lidImageSize;
};


class BpmConfigLidImage
{
public:

    /**
    * @brief Constructor that sets access to LID information
    *
    * @param[in] i_lidImageAddr  virtual address where LID was loaded
    * @param[in] i_size          size of the loaded LID
    */
    BpmConfigLidImage(void * const i_lidImageAddr, size_t i_size);

    /**
    * @brief Returns the version of the config binary as a uint16_t. There isn't
    *        a way to check the version of the config data on the BPM but the
    *        config binary still has the version of the flash image it
    *        originally came from.
    *
    * @return uint16_t   version of the firmware image as MMmm.
    *                    MM = major version, mm = minor.
    */
    uint16_t getVersion() const;

    /**
    * @brief Returns the number of fragments in the LID image.
    *
    */
    uint16_t getNumberOfFragments() const;

    /**
     * @brief Returns a pointer to the first fragment in LID image.
     */
    void const * getFirstFragment() const;

    /*   The binary will be organized in the following way:
     *   Byte 1:     Major version number (MM)
     *   Byte 2:     Minor version number (mm)
     *   Byte 3:     N number of fragments in the file (NN)
     *   Byte 4-EOF: Fragments of the form:
     *             FRAGMENT_SIZE   Byte 1:   X number of bytes in fragment data
     *                                       section. (XX)
     *             INDEX_OFFSET    Byte 2-3: Each BPM's config section is unique
     *                                       to itself. So, during the update
     *                                       the contents of a BPM's config data
     *                                       will be dumped into a buffer.
     *                                       These two bytes will be used as an
     *                                       offset into that buffer from which
     *                                       overwritting will take place.
     *                                       (IN DX)
     *             DATA_BYTES      Byte 4-X: Fragment data bytes to be written
     *                                       at the INDEX_OFFSET in the dumped
     *                                       config data buffer. (DD)
     *
     *   Example file output:
     *      01 05 01 04 01 28 6a 14 31 80
     *      MM mm NN XX IN DX DD DD DD DD
     */
    typedef struct config_image_header
    {
        uint8_t iv_versionMajor;
        uint8_t iv_versionMinor;
        uint16_t iv_numberOfFragments;
    } config_image_header_t;

private:

    // Pointer to the LID image allocated outside of the class
    void * const iv_lidImage;

    // The size of the LID image.
    size_t iv_lidImageSize;
};

class Bpm
{
    /*
     * The Bpm can either be in Bootstrap Loader (BSL) mode or not. Many of
     * member functions utilize BSL mode for the update procedure and must
     * therefore be in BSL mode to succeed. Other functions perform operations
     * that will not work in BSL mode since that mode is strictly for updating
     * the device and turns of some functionality while in that mode. The "mode"
     * the BPM must be in is given in the function brief description.
     */
public:


    explicit Bpm(const TARGETING::TargetHandle_t i_nvdimm);

    // Force User to supply a nvdimm target.
    Bpm() = delete;

    /**
     * @brief Runs the BPM firmware update using the given image.
     *
     * @param[in] i_image The BPM firmware image.
     *
     * @return  errlHndl_t  nullptr on success. Otherwise, pointer to an
     *                      errlEntry.
     */
    errlHndl_t runUpdate(BpmFirmwareLidImage i_fwImage,
                         BpmConfigLidImage   i_configImage);

    /**
     *  @brief At most, one full update retry should occur in some
     *         circumstances. If one of those occurances happens then the
     *         member iv_attemptAnotherUpdate will be set to true. Otherwise, it
     *         will remain false.
     *
     *  @return     bool        true if another update should be attempted.
     *                          Otherwise, false.
     */
    bool attemptAnotherUpdate();

    /**
     *  @brief Returns if an update has been attempted on this BPM.
     *
     *  @return     bool        true if an update has been attempted before.
     *                          Otherwise, false.
     */
    bool hasAttemptedUpdate();

    /**
     *  @brief returns the nvdimm that is associated with this BPM.
     */
    const TARGETING::TargetHandle_t getNvdimm();

private:

    // The nvdimm whose battery firmware will be updated.
    const TARGETING::TargetHandle_t iv_nvdimm;

    // The Bootstrap Loader version of the BPM
    uint8_t iv_bslVersion;

    // The firmware address for the BPM image can be either 0x8000 or 0xA000.
    // This member will keep track of which one it is.
    uint16_t iv_firmwareStartAddress;

    // Keeps track of if the update should be attempted again.
    bool iv_attemptAnotherUpdate;

    // Buffers for the segment data in case another update attempt is needed.
    // If the first update fails there won't be any running firmware on the
    // device which is required to dump the segment data.
    uint8_t iv_segmentD[SEGMENT_SIZE];
    uint8_t iv_segmentB[SEGMENT_SIZE];

    // Keeps track if the segments have been merged with the flash image data
    // yet.
    bool iv_segmentDMerged;
    bool iv_segmentBMerged;

    // Keeps track of if an update has been attempted at least once.
    bool iv_updateAttempted;

     /**
      * @brief Determines if another update attempt should occur for this BPM.
      */
    void setAttemptAnotherUpdate();

    /**
     * @brief Gets the BSL version from the BPM and sets the iv_bslVersion
     *        member. Only needs to be called once.
     *
     * @return  errlHndl_t  nullptr on success. Otherwise, pointer to an
     *                      errlEntry.
     */
    errlHndl_t readBslVersion();

    /**
     * @brief Gets the Firmware version from the BPM
     *
     * @param[out]  o_fwVersion     The firmware version currently on the BPM.
     *
     * @return  errlHndl_t  nullptr on success. Otherwise, pointer to an
     *                      errlEntry.
     */
    errlHndl_t getFwVersion(uint16_t & o_fwVersion) const;

    /**
     * @brief This function issues a command to the BPM using a payload as the
     *        means of sending the command.
     *
     * @param[in]   i_command   The BSP command to send to the BPM.
     * @param[in]   i_payload   The payload to write to the
     *                          BPM_REG_PAYLOAD_START register.
     * @param[in]   i_opType    The operation type of the command. Must be one
     *                          of the COMMAND_STATUS_REGISTER_OP_TYPES
     *
     * @param[in]   i_msDelay   How long to wait before the response from the
     *                          BPM should be checked. Default 1 ms. If a delay
     *                          of 0 ms is given then the response will not be
     *                          read and it is the caller's responsibilty to
     *                          check the response status. See COMMAND enum for
     *                          required delays.
     *
     * @return  errlHndl_t  nullptr on success. Otherwise, pointer to an
     *                      errlEntry.
     */
    errlHndl_t issueCommand(uint8_t i_command,
                            payload_t i_payload,
                            uint8_t i_opType,
                            int     i_msDelay = 1);

    /**
     * @brief This function issues a BSP command to the BPM by setting up a
     *        payload containing only that command and then calling the
     *        issueCommand function that accepts a payload as an argument.
     *
     *        NOTE: Since the BSP command is not a BSL command, it doesn't need
     *        to be formatted as a BSL payload but it still must be written to
     *        the BPM_REG_PAYLOAD_START register.
     *
     * @param[in]   i_bspCommand   The BSP command to send to the BPM.
     * @param[in]   i_command      The BCL command to be written to the
     *                             BPM_REG_PAYLOAD_START register. Must be one
     *                             of the BCL_ commands.
     * @param[in]   i_opType       The operation type of the BSP command. Must
     *                             be a COMMAND_STATUS_REGISTER_OP_TYPES
     *
     * @param[in]   i_msDelay   How long to wait before the response from the
     *                          BPM should be checked. Default 1 ms. If a delay
     *                          of 0 ms is given then the response will not be
     *                          read and it is the caller's responsibilty to
     *                          check the response status. See COMMAND enum for
     *                          required delays.
     *
     * @return  errlHndl_t  nullptr on success. Otherwise, pointer to an
     *                      errlEntry.
     */
    errlHndl_t issueCommand(uint8_t i_bspCommand,
                            uint8_t i_command,
                            uint8_t i_opType,
                            int     i_msDelay = 1);

    /**
     * @brief This function checks if the BPM has entered update mode
     *
     * @return  errlHndl_t  nullptr on success.
     *                      Otherwise, pointer to an errlEntry.
     */
    errlHndl_t inUpdateMode();

    /**
     * @brief Send the command to the BPM to enter update mode
     *
     * @return  errlHndl_t  nullptr if no errors occurred during command
     *                      execution. Otherwise, pointer to an errlEntry.
     */
    errlHndl_t enterUpdateMode();

    /**
     * @brief Send the command to the BPM to exit update mode
     *
     * @return  errlHndl_t  nullptr if no errors occurred during command
     *                      execution. Otherwise, pointer to an errlEntry.
     */
    errlHndl_t exitUpdateMode();

    /**
     * @brief Executes the firmware portion of the BPM update.
     *
     * @param[in]   i_image     The BPM firmware LID image to apply to the BPM.
     *
     * @return  errlHndl_t  nullptr if no errors occurred.
     *                      Otherwise, pointer to an errlEntry.
     */
    errlHndl_t updateFirmware(BpmFirmwareLidImage i_image);

    /**
     * @brief Helper function that executes the firmware portion of the BPM
     *        update by calling all necessary functions in order.
     *
     * @param[in]   i_image     The BPM firmware LID image to apply to the BPM.
     *
     * @return  errlHndl_t  nullptr if no errors occurred.
     *                      Otherwise, pointer to an errlEntry.
     */
    errlHndl_t runFirmwareUpdates(BpmFirmwareLidImage i_image);

    /**
     *  @brief Executes the config portion of the BPM update.
     *
     *  @return errlHndl_t  nullptr on success. Otherwise, an Error.
     */
    errlHndl_t updateConfig();

    /**
     *  @brief Helper function that executes the config portion of the BPM
     *         update by calling all necessary functions in order.
     *
     * @param[in]   i_image     The BPM config LID image to apply to the BPM.
     *
     *  @return errlHndl_t  nullptr on success. Otherwise, an Error.
     */
    errlHndl_t runConfigUpdates(BpmConfigLidImage i_image);

    /**
     * @brief Commands the BPM to enter BSL mode to allow for BSL commands to be
     *        executed.
     *
     * @return  errlHndl_t  nullptr on success. Otherwise, pointer to an
     *                      errlEntry.
     */
    errlHndl_t enterBootstrapLoaderMode();

    /**
     * @brief Creates a valid BSL payload given a firmware_image_block_t.
     *
     * @param[out]  o_payload   The BSL payload
     * @param[in]   i_block     A pointer to a firmware image block.
     * @param[in]   i_command   The BSL command to be included with the payload
     *
     * @return  errlHndl_t  nullptr on success. Otherwise, pointer to an
     *                      errlEntry.
     */
    errlHndl_t setupPayload(payload_t                    & o_payload,
                            const firmware_image_block_t * i_block,
                            uint8_t                        i_command);

    /**
     * @brief Creates a valid BSL payload given a BSL command, address, and
     *        optionally data to include with the command. This function is used
     *        to create firmware_image_block_t objects which are then passed
     *        onto the version of setupPayload that turns them into payloads.
     *
     * @param[out]  o_payload   The BSL payload
     * @param[in]   i_command   The BSL command to be included with the payload
     * @param[in]   i_address   The address to execute the command from. This
     *                          will be zero or the address to execute the
     *                          command from.
     * @param[in]   i_data      The array of data to be included with the BSL
     *                          command. Default nullptr.
     * @param[in]   i_length    Length of the i_data array parameter. Default 0.
     *
     * @return  errlHndl_t  nullptr on success. Otherwise, pointer to an
     *                      errlEntry.
     */
    errlHndl_t setupPayload(payload_t & o_payload,
                            uint8_t     i_command,
                            uint16_t    i_address,
                      const uint8_t     i_data[] = nullptr,
                            size_t      i_length = 0);

    /**
     * @brief This function unlocks the BPM.
     *
     * @return  errlHndl_t  nullptr on success. Otherwise, pointer to an
     *                      errlEntry.
     */
    errlHndl_t unlockDevice();

    /**
     * @brief This function will send the command to reset the BPM. This will
     *        exit BSL mode if the BPM was in that mode.
     *
     * @return  errlHndl_t  nullptr on success. Otherwise, pointer to an
     *                      errlEntry.
     */
    errlHndl_t resetDevice();

    /**
     *  @brief Write to the BPM register via the SCAP registers
     *
     *  @param[in]      i_reg       The BPM register to write to.
     *
     *  @param[in]      i_data      The data to write to the given register.
     *
     *  @return         errlHndl_t  nullptr on success. Otherwise, an error.
     */
    errlHndl_t writeViaScapRegister(uint8_t i_reg, uint8_t i_data);

    /**
     *  @brief Reads the BPM register via the SCAP registers
     *
     *  @param[in]      i_reg       The BPM register to read from.
     *
     *  @param[in/out]  io_data     The data that was in the given register.
     *
     *  @return         errlHndl_t  nullptr on success. Otherwise, an error.
     */
    errlHndl_t readViaScapRegister(uint8_t i_reg, uint8_t & io_data);

    /**
     *  @brief Disables write protection on the BPM by sending the password
     *         sequence to I2C_REG_PROTECT
     *
     *  @return     errlHndl_t      nullptr on success. Otherwise, an error.
     */
    errlHndl_t disableWriteProtection();

    /**
     *  @brief Many operations performed on the BPM require the magic registers
     *         to have specific values written in them. This function acts as a
     *         helper to facilitate that process.
     *
     *         NOTE: Write protection on the BPM must be disabled, otherwise
     *               this function will fail.
     *
     *  @param[in]  i_magicValues   The pair of magic values to be written to
     *                              BPM_MAGIC_REG1 and BPM_MAGIC_REG2
     *                              respectively.
     *
     *  @return     errlHndl_t      nullptr on success. Otherwise, an error.
     */
    errlHndl_t writeToMagicRegisters(
            uint8_t const (&i_magicValues)[NUM_MAGIC_REGISTERS]);

    /**
     *  @brief Switches the page on the BPM to the given page. This function
     *         must be executed only after the segment read magic values have
     *         been written to the BPM's magic registers.
     *
     *  @param[in]  i_segmentCode   The segment code that corresponds to the
     *                              page to switch to on the BPM.
     *
     *  @return     errlHndl_t      nullptr on success. Otherwise, an error
     *
     */
    errlHndl_t switchBpmPage(uint16_t i_segmentCode);

    /**
     *  @brief Dumps the given segment data from the BPM. CANNOT be in BSL mode.
     *
     *  @param[in]  i_segmentCode   The segment code that corresponds to the
     *                              segment to dump from the BPM.
     *
     *  @param[out] o_buffer        A pointer to the buffer to fill with segment
     *                              data. Must be SEGMENT_SIZE in size.
     *
     *  @return     errlHndl_t      nullptr on success. Otherwise, an error
     *
     */
    errlHndl_t dumpSegment(uint16_t i_segmentCode,
                           uint8_t  (&o_buffer)[SEGMENT_SIZE]);

    /**
     *  @brief Merges the segment data dumped from the BPM with the segment data
     *         fragments present in the BpmConfigLidImage that correspond to the
     *         given segment code.
     *
     *  @param[in]  i_configImage      The image that holds the fragments of
     *                                 segment data.
     *
     *  @param[in]  i_segmentCode      The segment code that corresponds to the
     *                                 segment to dump from the BPM.
     *
     *  @param[out] o_buffer           The merged segment data for the BPM.
     *                                 Must be SEGMENT_SIZE in length.
     *
     *  @return     errlHndl_t         nullptr on success. Otherwise, an error.
     */
    errlHndl_t mergeSegment(BpmConfigLidImage i_configImage,
                            uint16_t          i_segmentCode,
                            uint8_t           (&o_buffer)[SEGMENT_SIZE]);

    /**
     *  @brief Commands the BPM to erase the segment data on the BPM using the
     *         given segment code to tell it which to erase.
     *         The BPM must be in BSL mode for this function to work.
     *
     *  @param[in]  i_segmentCode   The segment from the config data section to
     *                              erase.
     *
     *  @return     errlHndl_t      nullptr on success. Otherwise, an error.
     */
    errlHndl_t eraseSegment(uint16_t i_segmentCode);

    /**
     *  @brief Writes the segment data from the buffer to the BPM using the
     *         given segment code to determine which segment the data belongs
     *         to. The BPM must be in BSL mode for this function to work.
     *
     *  @param[in]  i_buffer        The segment data to write to the BPM.
     *
     *  @param[in]  i_segmentCode   The segment from the config data section the
     *                              data belongs to.
     *
     *  @return     errlHndl_t      nullptr on success. Otherwise, an error.
     */
    errlHndl_t writeSegment(uint8_t const (&i_buffer)[SEGMENT_SIZE],
                            uint16_t i_segmentCode);

    /**
     *  @brief Dumps segment D and B data from the BPM and merges it with the
     *         data from the config image to create the unique updated segments
     *         for this BPM. The BPM CANNOT be in BSL mode for this function to
     *         work because the data is dumped using SCAP registers. There must
     *         also be working firmware on the device otherwise this will fail.
     *
     *  @param[in]  i_configImage   The config image that has the fragments to
     *                              merge into the BPM's existing segment data.
     *
     *  @return     errlHndl_t      nullptr on success. Otherwise, an error.
     */
    errlHndl_t preprocessSegments(BpmConfigLidImage i_configImage);

    /**
     *  @brief  Verifies that the data written into the flash on the BPM is what
     *          was sent by hostboot in a payload.
     *
     *  @param[in]  i_payload       The payload that was just sent to the BPM to
     *                              be verified.
     *
     *  @param[in]  i_dataLength    The length of the data section of the
     *                              payload.
     *
     *  @param[in]  o_status        The status code returned from the BPM.
     *                              A status of 0 indicates success, all other
     *                              values are a failure.
     *
     *  @return     errlHndl_t      nullptr if no errors. Otherwise, an error.
     */
    errlHndl_t verifyBlockWrite(payload_t i_payload,
                                uint8_t   i_dataLength,
                                uint8_t & o_status);

    /**
     *  @brief Attempts a BSL_RX_DATA_BLOCK command up to three times by calling
     *         blockWriteRetry.
     *
     *  @param[in]  i_payload       The payload containing the BSL_RX_DATA_BLOCK
     *                              command and the data to be attempted to be
     *                              written.
     *
     *  @return     errlHndl_t      nullptr on success. Otherwise, an error.
     */
    errlHndl_t blockWrite(payload_t i_payload);

    /**
     *  @brief Attempts a BSL_RX_DATA_BLOCK command up to three times.
     *
     *  @param[in]  i_payload       The payload containing the BSL_RX_DATA_BLOCK
     *                              command and the data to be attempted to be
     *                              written.
     *
     *  @return     errlHndl_t      nullptr on success. Otherwise, an error.
     */
    errlHndl_t blockWriteRetry(payload_t i_payload);

    /**
     * @brief A helper function used to wait for the command status bit to reset
     *        after a command is executed.
     *
     * @param[in]   i_commandStatus     The command status register union made
     *                                  by the caller to identify the type of
     *                                  command that was sent.
     *
     * @return      errlHndl_t          nullptr on success. Otherwise, an error.
     */
    errlHndl_t waitForCommandStatusBitReset(
            command_status_register_t i_commandStatus);

    errlHndl_t verifyGoodBpmState();

    /**
     *  @brief Helper function for the SCAP register functions that will poll
     *         the busy bit in SCAP_STATUS until it is zero.
     *
     *  @return     errlHndl_t      nullptr on success. Otherwise, an error.
     */
    errlHndl_t waitForBusyBit();

    /**
     *  @brief Starting with BSL version 1.4 it is necessary to check the CRC of
     *         the firmware image once it has been written to the BPM. If this
     *         is not done or fails to succeed then the firmware image will not
     *         be loaded and executed by the BPM. If the CRC check fails then
     *         the update must be attempted again.
     *         Must be in BSL mode.
     *
     *  @return     errlHndl_t      nullptr on success. Otherwise, an error.
     */
    errlHndl_t checkFirmwareCrc();

    /**
     *  @brief After a command is sent to the BPM to request info from it this
     *         function processes the response and returns it to the caller.
     *         A response packet can only be received once per command sent to
     *         the BPM. Which means that the caller must resend the command
     *         again to get another response packet. Simply calling the function
     *         repeatedly will not work. BPM must be in BSL mode.
     *
     *  @param[in]  o_responseData      The buffer to be filled with the
     *                                  response data from the BPM.
     *
     *  @param[in]  i_responseSize      The size of the buffer to be filled.
     *
     *  @return     errlHndl_t          nullptr on success. Otherwise, an error.
     */
    errlHndl_t getResponse(uint8_t * o_responseData,
                           uint8_t   i_responseSize);


    /**
     *  @brief Helper function to handle two potential errors that might occur in a
     *         function that only returns a single error log. If the return error is
     *         not nullptr then the second error will be linked to it and committed
     *         if this is the final update attempt. Otherwise, it will be deleted
     *         since the update procedure will occur again and may be successful.
     *         If the return error is nullptr then the return error will point to
     *         the second's error and the second error will point to nullptr.
     *
     *  @param[in/out]      io_returnErrl   A pointer to the error that would be
     *                                      returned by the function that called
     *                                      this one. If nullptr, then it will be
     *                                      set point to the secondary error and
     *                                      that error will become nullptr.
     *
     *  @param[in/out]     io_secondErrl    The secondary error that occurred which
     *                                      in addition to the usual returned error.
     */
    void handleMultipleErrors(errlHndl_t& io_returnErrl,
                              errlHndl_t& io_secondErrl);

    /**
     * @brief Calculates the CRC16 bytes for the BSL payload. This CRC differs
     *        from the NVDIMM CRC calculation in that the initial value is
     *        0xFFFF instead of 0x0000.
     *
     *        NOTE: To calculate a correct CRC for the BSL payload the SYNC_BYTE
     *              must be included in the payload despite the fact that it
     *              should be removed from the payload before sending to the BPM
     *              because the NVDIMM sends the SYNC_BYTE automatically.
     *
     * @param[in]   i_ptr    A pointer to the start of the data to calculate the
     *                       CRC for.
     * @param[in]   i_size   This size of the data pointed at by i_ptr.
     *
     * @return      uint16_t The CRC bytes.
     */
    uint16_t crc16_calc(const void* const i_ptr, int i_size);


};

typedef std::vector<Bpm> bpmList_t;

/**
 * @brief Runs the firmware and config updates on the list of BPMs given.
 *
 * @param[in] i_16gb_BPMs   The list of BPMs sitting on 16gb NVDIMMs that
 *                          potentially need to be updated.
 *
 * @param[in] i_32gb_BPMs   The list of BPMs sitting on 32gb NVDIMMs that
 *                          potentially need to be updated.
 *
 * @param[in] i_16gb_fwImage    The firmware image associated with BPMs sitting
 *                              on 16gb NVDIMMs.
 *
 * @param[in] i_32gb_fwImage    The firmware image associated with BPMs sitting
 *                              on 32gb NVDIMMs.
 *
 * @param[in] i_16gb_configImage    The configuration data associated with BPMs
 *                                  sitting on 16gb NVDIMMs.
 *
 * @param[in] i_32gb_configImage    The configuration data associated with BPMs
 *                                  sitting on 32gb NVDIMMs.
 *
 */
void runBpmUpdates(bpmList_t * const i_16gb_BPMs,
                   bpmList_t * const i_32gb_BPMs,
                   BpmFirmwareLidImage * const i_16gb_fwImage,
                   BpmFirmwareLidImage * const i_32gb_fwImage,
                   BpmConfigLidImage * const i_16gb_configImage,
                   BpmConfigLidImage * const i_32gb_configImage);

}; // end of BPM namespace
}; // end of NVDIMM namespace

#endif

OpenPOWER on IntegriCloud