1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <stdio.h>
6#include <stdlib.h>
7
8#include <fbl/alloc_checker.h>
9#include <fbl/unique_ptr.h>
10#include <unittest/unittest.h>
11#include <zircon/device/ram-nand.h>
12#include <zircon/process.h>
13
14#include "fake-ddk.h"
15#include "ram-nand.h"
16
17namespace {
18
19constexpr int kPageSize = 4096;
20constexpr int kOobSize = 4;
21constexpr int kBlockSize = 4;
22constexpr int kNumBlocks = 5;
23constexpr int kNumPages = kBlockSize * kNumBlocks;
24
25ram_nand_info_t BuildConfig() {
26    return ram_nand_info_t{
27        .vmo = 0,
28        .nand_info = {4096, 4, 5, 6, 0, NAND_CLASS_FTL, {}},
29        .export_nand_config = false,
30        .export_partition_map = false,
31        .bad_block_config = {},
32        .extra_partition_config_count = 0,
33        .extra_partition_config = {},
34        .partition_map = {},
35    };
36}
37
38bool TrivialLifetimeTest() {
39    BEGIN_TEST;
40    NandParams params(kPageSize, kBlockSize, kNumBlocks, 6, 0);  // 6 bits of ECC, no OOB.
41    char name[NAME_MAX];
42    {
43        NandDevice device(params);
44
45        ASSERT_EQ(ZX_OK, device.Init(name, zx::vmo()));
46        EXPECT_EQ(0, strncmp("ram-nand-0", name, NAME_MAX));
47    }
48    {
49        NandDevice device(params);
50
51        ASSERT_EQ(ZX_OK, device.Init(name, zx::vmo()));
52        EXPECT_EQ(0, strncmp("ram-nand-1", name, NAME_MAX));
53    }
54    END_TEST;
55}
56
57bool DdkLifetimeTest() {
58    BEGIN_TEST;
59    NandParams params(kPageSize, kBlockSize, kNumBlocks, 6, 0);  // 6 bits of ECC, no OOB.
60    NandDevice* device(new NandDevice(params, fake_ddk::kFakeParent));
61
62    fake_ddk::Bind ddk;
63    ASSERT_EQ(ZX_OK, device->Bind(BuildConfig()));
64    device->DdkUnbind();
65    EXPECT_TRUE(ddk.Ok());
66
67    // This should delete the object, which means this test should not leak.
68    device->DdkRelease();
69    END_TEST;
70}
71
72fbl::unique_ptr<NandDevice> CreateDevice(size_t* operation_size) {
73    NandParams params(kPageSize, kBlockSize, kNumBlocks, 6, kOobSize);  // 6 bits of ECC.
74    fbl::AllocChecker checker;
75    fbl::unique_ptr<NandDevice> device(new (&checker) NandDevice(params));
76    if (!checker.check()) {
77        return nullptr;
78    }
79
80    if (operation_size) {
81        nand_info_t info;
82        device->Query(&info, operation_size);
83    }
84
85    char name[NAME_MAX];
86    if (device->Init(name, zx::vmo()) != ZX_OK) {
87        return nullptr;
88    }
89    return fbl::move(device);
90}
91
92bool BasicDeviceProtocolTest() {
93    BEGIN_TEST;
94    NandParams params(kPageSize, kBlockSize, kNumBlocks, 6, 0);  // 6 bits of ECC, no OOB.
95    NandDevice device(params);
96
97    char name[NAME_MAX];
98    ASSERT_EQ(ZX_OK, device.Init(name, zx::vmo()));
99
100    ASSERT_EQ(kPageSize * kNumPages, device.DdkGetSize());
101
102    device.DdkUnbind();
103
104    ASSERT_EQ(ZX_ERR_BAD_STATE,
105              device.DdkIoctl(IOCTL_RAM_NAND_UNLINK, nullptr, 0, nullptr, 0, nullptr));
106    END_TEST;
107}
108
109bool UnlinkTest() {
110    BEGIN_TEST;
111    fbl::unique_ptr<NandDevice> device = CreateDevice(nullptr);
112    ASSERT_TRUE(device);
113
114    ASSERT_EQ(ZX_OK, device->DdkIoctl(IOCTL_RAM_NAND_UNLINK, nullptr, 0, nullptr, 0, nullptr));
115
116    // The device is "dead" now.
117    ASSERT_EQ(ZX_ERR_BAD_STATE,
118              device->DdkIoctl(IOCTL_RAM_NAND_UNLINK, nullptr, 0, nullptr, 0, nullptr));
119    END_TEST;
120}
121
122bool QueryTest() {
123    BEGIN_TEST;
124    NandParams params(kPageSize, kBlockSize, kNumBlocks, 6, 8);  // 6 bits of ECC, 8 OOB bytes.
125    NandDevice device(params);
126
127    nand_info_t info;
128    size_t operation_size;
129    device.Query(&info, &operation_size);
130    ASSERT_EQ(0, memcmp(&info, &params, sizeof(info)));
131    ASSERT_GT(operation_size, sizeof(nand_op_t));
132    END_TEST;
133}
134
135// Tests setting and getting bad blocks.
136bool FactoryBadBlockListTest() {
137    BEGIN_TEST;
138    fbl::unique_ptr<NandDevice> device = CreateDevice(nullptr);
139    ASSERT_TRUE(device);
140
141    uint32_t bad_blocks[] = {1, 3, 5};
142    ASSERT_EQ(ZX_ERR_NOT_SUPPORTED,
143              device->DdkIoctl(IOCTL_RAM_NAND_SET_BAD_BLOCKS, bad_blocks, sizeof(bad_blocks),
144                               nullptr, 0, nullptr));
145
146    uint32_t result[4];
147    uint32_t num_bad_blocks;
148    device->GetFactoryBadBlockList(result, sizeof(result), &num_bad_blocks);
149    ASSERT_EQ(0, num_bad_blocks);
150    END_TEST;
151}
152
153// Data to be pre-pended to a nand_op_t issued to the device.
154struct OpHeader {
155    class Operation* operation;
156    class NandTest* test;
157};
158
159// Wrapper for a nand_op_t.
160class Operation {
161  public:
162    explicit Operation(size_t op_size, NandTest* test = 0)
163        : op_size_(op_size + sizeof(OpHeader)), test_(test) {}
164    ~Operation() {
165        if (mapped_addr_) {
166            zx_vmar_unmap(zx_vmar_root_self(), reinterpret_cast<uintptr_t>(mapped_addr_),
167                          buffer_size_);
168        }
169    }
170
171    // Accessors for the memory represented by the operation's vmo.
172    size_t buffer_size() const { return buffer_size_; }
173    char* buffer() const { return mapped_addr_; }
174
175    // Creates a vmo and sets the handle on the nand_op_t.
176    bool SetDataVmo();
177    bool SetOobVmo();
178
179    nand_op_t* GetOperation();
180
181    void OnCompletion(zx_status_t status) {
182        status_ = status;
183        completed_ = true;
184    }
185
186    bool completed() const { return completed_; }
187    zx_status_t status() const { return status_; }
188
189  private:
190    zx_handle_t GetVmo();
191    void CreateOperation();
192
193    zx::vmo vmo_;
194    char* mapped_addr_ = nullptr;
195    size_t op_size_;
196    NandTest* test_;
197    zx_status_t status_ = ZX_ERR_ACCESS_DENIED;
198    bool completed_ = false;
199    static constexpr size_t buffer_size_ = (kPageSize + kOobSize) * kNumPages;
200    fbl::unique_ptr<char[]> raw_buffer_;
201    DISALLOW_COPY_ASSIGN_AND_MOVE(Operation);
202};
203
204bool Operation::SetDataVmo() {
205    nand_op_t* operation = GetOperation();
206    if (!operation) {
207        return false;
208    }
209    operation->rw.data_vmo = GetVmo();
210    return operation->rw.data_vmo != ZX_HANDLE_INVALID;
211}
212
213bool Operation::SetOobVmo() {
214    nand_op_t* operation = GetOperation();
215    if (!operation) {
216        return false;
217    }
218    operation->rw.oob_vmo = GetVmo();
219    return operation->rw.oob_vmo != ZX_HANDLE_INVALID;
220}
221
222nand_op_t* Operation::GetOperation() {
223    if (!raw_buffer_) {
224        CreateOperation();
225    }
226    return reinterpret_cast<nand_op_t*>(raw_buffer_.get() + sizeof(OpHeader));
227}
228
229zx_handle_t Operation::GetVmo() {
230    if (vmo_.is_valid()) {
231        return vmo_.get();
232    }
233
234    zx_status_t status = zx::vmo::create(buffer_size_, 0, &vmo_);
235    if (status != ZX_OK) {
236        return ZX_HANDLE_INVALID;
237    }
238
239    uintptr_t address;
240    status = zx_vmar_map(zx_vmar_root_self(),
241                         ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
242                         0, vmo_.get(), 0, buffer_size_, &address);
243    if (status != ZX_OK) {
244        return ZX_HANDLE_INVALID;
245    }
246    mapped_addr_ = reinterpret_cast<char*>(address);
247    return vmo_.get();
248}
249
250void Operation::CreateOperation() {
251    fbl::AllocChecker checker;
252    raw_buffer_.reset(new (&checker) char[op_size_]);
253    if (!checker.check()) {
254        return;
255    }
256
257    memset(raw_buffer_.get(), 0, op_size_);
258    OpHeader* header = reinterpret_cast<OpHeader*>(raw_buffer_.get());
259    header->operation = this;
260    header->test = test_;
261}
262
263// Provides control primitives for tests that issue IO requests to the device.
264class NandTest {
265  public:
266    NandTest() {}
267    ~NandTest() {}
268
269    static void CompletionCb(nand_op_t* op, zx_status_t status) {
270        OpHeader* header =
271                reinterpret_cast<OpHeader*>(reinterpret_cast<char*>(op) - sizeof(OpHeader));
272
273        header->operation->OnCompletion(status);
274        header->test->num_completed_++;
275        sync_completion_signal(&header->test->event_);
276    }
277
278    bool Wait() {
279        zx_status_t status = sync_completion_wait(&event_, ZX_SEC(5));
280        sync_completion_reset(&event_);
281        return status == ZX_OK;
282    }
283
284    bool WaitFor(int desired) {
285        while (num_completed_ < desired) {
286            if (!Wait()) {
287                return false;
288            }
289        }
290        return true;
291    }
292
293  private:
294    sync_completion_t event_;
295    int num_completed_ = 0;
296    DISALLOW_COPY_ASSIGN_AND_MOVE(NandTest);
297};
298
299// Tests trivial attempts to queue one operation.
300bool QueueOneTest() {
301    BEGIN_TEST;
302
303    size_t op_size;
304    fbl::unique_ptr<NandDevice> device = CreateDevice(&op_size);
305    ASSERT_TRUE(device);
306
307    NandTest test;
308    Operation operation(op_size, &test);
309
310    nand_op_t* op = operation.GetOperation();
311    ASSERT_TRUE(op);
312
313    op->rw.command = NAND_OP_WRITE;
314    op->completion_cb = &NandTest::CompletionCb;
315    device->Queue(op);
316
317    ASSERT_TRUE(test.Wait());
318    ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
319
320    op->rw.length = 1;
321    device->Queue(op);
322    ASSERT_TRUE(test.Wait());
323    ASSERT_EQ(ZX_ERR_BAD_HANDLE, operation.status());
324
325    op->rw.offset_nand = kNumPages;
326    device->Queue(op);
327    ASSERT_TRUE(test.Wait());
328    ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
329
330    ASSERT_TRUE(operation.SetDataVmo());
331
332    op->rw.offset_nand = kNumPages - 1;
333    device->Queue(op);
334    ASSERT_TRUE(test.Wait());
335    ASSERT_EQ(ZX_OK, operation.status());
336
337    END_TEST;
338}
339
340// Verifies that the buffer pointed to by the operation's vmo contains the given
341// pattern for the desired number of pages, skipping the pages before start.
342bool CheckPattern(uint8_t what, int start, int num_pages, const Operation& operation) {
343    const char* buffer = operation.buffer() + kPageSize * start;
344    for (int i = 0; i < kPageSize * num_pages; i++) {
345        if (static_cast<uint8_t>(buffer[i]) != what) {
346            return false;
347        }
348    }
349    return true;
350}
351
352// Prepares the operation to write num_pages starting at offset.
353void SetForWrite(int offset, int num_pages, Operation* operation) {
354    nand_op_t* op = operation->GetOperation();
355    op->rw.command = NAND_OP_WRITE;
356    op->rw.length = num_pages;
357    op->rw.offset_nand = offset;
358    op->completion_cb = &NandTest::CompletionCb;
359}
360
361// Prepares the operation to read num_pages starting at offset.
362void SetForRead(int offset, int num_pages, Operation* operation) {
363    nand_op_t* op = operation->GetOperation();
364    op->rw.command = NAND_OP_READ;
365    op->rw.length = num_pages;
366    op->rw.offset_nand = offset;
367    op->completion_cb = &NandTest::CompletionCb;
368}
369
370bool ReadWriteTest() {
371    BEGIN_TEST;
372
373    size_t op_size;
374    fbl::unique_ptr<NandDevice> device = CreateDevice(&op_size);
375    ASSERT_TRUE(device);
376
377    NandTest test;
378    Operation operation(op_size, &test);
379    ASSERT_TRUE(operation.SetDataVmo());
380    memset(operation.buffer(), 0x55, operation.buffer_size());
381
382    nand_op_t* op = operation.GetOperation();
383    op->rw.corrected_bit_flips = 125;
384
385    SetForWrite(4, 4, &operation);
386    device->Queue(op);
387
388    ASSERT_TRUE(test.Wait());
389    ASSERT_EQ(ZX_OK, operation.status());
390    ASSERT_EQ(125, op->rw.corrected_bit_flips);  // Doesn't modify the value.
391
392    op->rw.command = NAND_OP_READ;
393    memset(operation.buffer(), 0, operation.buffer_size());
394
395    device->Queue(op);
396    ASSERT_TRUE(test.Wait());
397    ASSERT_EQ(ZX_OK, operation.status());
398    ASSERT_EQ(0, op->rw.corrected_bit_flips);
399    ASSERT_TRUE(CheckPattern(0x55, 0, 4, operation));
400
401    END_TEST;
402}
403
404// Tests that a new device is filled with 0xff (as a new nand chip).
405bool NewChipTest() {
406    BEGIN_TEST;
407
408    size_t op_size;
409    fbl::unique_ptr<NandDevice> device = CreateDevice(&op_size);
410    ASSERT_TRUE(device);
411
412    NandTest test;
413    Operation operation(op_size, &test);
414    ASSERT_TRUE(operation.SetDataVmo());
415    ASSERT_TRUE(operation.SetOobVmo());
416    memset(operation.buffer(), 0x55, operation.buffer_size());
417
418    nand_op_t* op = operation.GetOperation();
419    op->rw.corrected_bit_flips = 125;
420
421    SetForRead(0, kNumPages, &operation);
422    op->rw.offset_oob_vmo = kNumPages;
423    device->Queue(op);
424
425    ASSERT_TRUE(test.Wait());
426    ASSERT_EQ(ZX_OK, operation.status());
427    ASSERT_EQ(0, op->rw.corrected_bit_flips);
428
429    ASSERT_TRUE(CheckPattern(0xff, 0, kNumPages, operation));
430
431    // Verify OOB area.
432    memset(operation.buffer(), 0xff, kOobSize * kNumPages);
433    ASSERT_EQ(0,
434              memcmp(operation.buffer() + kPageSize * kNumPages, operation.buffer(),
435                     kOobSize * kNumPages));
436
437    END_TEST;
438}
439
440// Tests serialization of multiple reads and writes.
441bool QueueMultipleTest() {
442    BEGIN_TEST;
443
444    size_t op_size;
445    fbl::unique_ptr<NandDevice> device = CreateDevice(&op_size);
446    ASSERT_TRUE(device);
447
448    NandTest test;
449    fbl::unique_ptr<Operation> operations[10];
450    for (int i = 0; i < 10; i++) {
451        fbl::AllocChecker checker;
452        operations[i].reset(new (&checker) Operation(op_size, &test));
453        ASSERT_TRUE(checker.check());
454        Operation& operation = *(operations[i].get());
455        ASSERT_TRUE(operation.SetDataVmo());
456        memset(operation.buffer(), i + 30, operation.buffer_size());
457    }
458
459    SetForWrite(0, 1, operations[0].get());  // 0 x x x x x
460    SetForWrite(1, 3, operations[1].get());  // 0 1 1 1 x x
461    SetForRead(0, 4, operations[2].get());
462    SetForWrite(4, 2, operations[3].get());  // 0 1 1 1 3 3
463    SetForRead(2, 4, operations[4].get());
464    SetForWrite(2, 2, operations[5].get());  // 0 1 5 5 3 3
465    SetForRead(0, 4, operations[6].get());
466    SetForWrite(0, 4, operations[7].get());  // 7 7 7 7 3 3
467    SetForRead(2, 4, operations[8].get());
468    SetForRead(0, 2, operations[9].get());
469
470    for (const auto& operation : operations) {
471        nand_op_t* op = operation->GetOperation();
472        device->Queue(op);
473    }
474
475    ASSERT_TRUE(test.WaitFor(10));
476
477    for (const auto& operation : operations) {
478        ASSERT_EQ(ZX_OK, operation->status());
479        ASSERT_TRUE(operation->completed());
480    }
481
482    ASSERT_TRUE(CheckPattern(30, 0, 1, *(operations[2].get())));
483    ASSERT_TRUE(CheckPattern(31, 1, 3, *(operations[2].get())));
484
485    ASSERT_TRUE(CheckPattern(31, 0, 2, *(operations[4].get())));
486    ASSERT_TRUE(CheckPattern(33, 2, 2, *(operations[4].get())));
487
488    ASSERT_TRUE(CheckPattern(30, 0, 1, *(operations[6].get())));
489    ASSERT_TRUE(CheckPattern(31, 1, 1, *(operations[6].get())));
490    ASSERT_TRUE(CheckPattern(35, 2, 2, *(operations[6].get())));
491
492    ASSERT_TRUE(CheckPattern(37, 0, 2, *(operations[8].get())));
493    ASSERT_TRUE(CheckPattern(33, 2, 2, *(operations[8].get())));
494
495    ASSERT_TRUE(CheckPattern(37, 0, 2, *(operations[9].get())));
496
497    END_TEST;
498}
499
500bool OobLimitsTest() {
501    BEGIN_TEST;
502
503    size_t op_size;
504    fbl::unique_ptr<NandDevice> device = CreateDevice(&op_size);
505    ASSERT_TRUE(device);
506
507    NandTest test;
508    Operation operation(op_size, &test);
509
510    nand_op_t* op = operation.GetOperation();
511    op->rw.command = NAND_OP_READ;
512    op->completion_cb = &NandTest::CompletionCb;
513
514    device->Queue(op);
515    ASSERT_TRUE(test.Wait());
516    ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
517
518    op->rw.length = 1;
519    device->Queue(op);
520    ASSERT_TRUE(test.Wait());
521    ASSERT_EQ(ZX_ERR_BAD_HANDLE, operation.status());
522
523    op->rw.offset_nand = kNumPages;
524    device->Queue(op);
525    ASSERT_TRUE(test.Wait());
526    ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
527
528    ASSERT_TRUE(operation.SetOobVmo());
529
530    op->rw.offset_nand = kNumPages - 1;
531    device->Queue(op);
532    ASSERT_TRUE(test.Wait());
533    ASSERT_EQ(ZX_OK, operation.status());
534
535    op->rw.length = 5;
536    device->Queue(op);
537    ASSERT_TRUE(test.Wait());
538    ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
539
540    END_TEST;
541}
542
543bool ReadWriteOobTest() {
544    BEGIN_TEST;
545
546    size_t op_size;
547    fbl::unique_ptr<NandDevice> device = CreateDevice(&op_size);
548    ASSERT_TRUE(device);
549
550    NandTest test;
551    Operation operation(op_size, &test);
552    ASSERT_TRUE(operation.SetOobVmo());
553
554    const char desired[kOobSize] = { 'a', 'b', 'c', 'd' };
555    memcpy(operation.buffer(), desired, kOobSize);
556
557    nand_op_t* op = operation.GetOperation();
558    op->rw.corrected_bit_flips = 125;
559
560    SetForWrite(2, 1, &operation);
561    device->Queue(op);
562
563    ASSERT_TRUE(test.Wait());
564    ASSERT_EQ(ZX_OK, operation.status());
565    ASSERT_EQ(125, op->rw.corrected_bit_flips);  // Doesn't modify the value.
566
567    op->rw.command = NAND_OP_READ;
568    op->rw.length = 2;
569    op->rw.offset_nand = 1;
570    memset(operation.buffer(), 0, kOobSize * 2);
571
572    device->Queue(op);
573    ASSERT_TRUE(test.Wait());
574    ASSERT_EQ(ZX_OK, operation.status());
575    ASSERT_EQ(0, op->rw.corrected_bit_flips);
576
577    // The "second page" has the data of interest.
578    ASSERT_EQ(0, memcmp(operation.buffer() + kOobSize, desired, kOobSize));
579
580    END_TEST;
581}
582
583bool ReadWriteDataAndOobTest() {
584    BEGIN_TEST;
585
586    size_t op_size;
587    fbl::unique_ptr<NandDevice> device = CreateDevice(&op_size);
588    ASSERT_TRUE(device);
589
590    NandTest test;
591    Operation operation(op_size, &test);
592    ASSERT_TRUE(operation.SetDataVmo());
593    ASSERT_TRUE(operation.SetOobVmo());
594
595    memset(operation.buffer(), 0x55, kPageSize * 2);
596    memset(operation.buffer() + kPageSize * 2, 0xaa, kOobSize * 2);
597
598    nand_op_t* op = operation.GetOperation();
599    op->rw.corrected_bit_flips = 125;
600
601    SetForWrite(2, 2, &operation);
602    op->rw.offset_oob_vmo = 2;  // OOB is right after data.
603    device->Queue(op);
604
605    ASSERT_TRUE(test.Wait());
606    ASSERT_EQ(ZX_OK, operation.status());
607    ASSERT_EQ(125, op->rw.corrected_bit_flips);  // Doesn't modify the value.
608
609    op->rw.command = NAND_OP_READ;
610    memset(operation.buffer(), 0, kPageSize * 4);
611
612    device->Queue(op);
613    ASSERT_TRUE(test.Wait());
614    ASSERT_EQ(ZX_OK, operation.status());
615    ASSERT_EQ(0, op->rw.corrected_bit_flips);
616
617    // Verify data.
618    ASSERT_TRUE(CheckPattern(0x55, 0, 2, operation));
619
620    // Verify OOB.
621    memset(operation.buffer(), 0xaa, kPageSize);
622    ASSERT_EQ(0, memcmp(operation.buffer() + kPageSize * 2, operation.buffer(), kOobSize * 2));
623
624    END_TEST;
625}
626
627bool EraseLimitsTest() {
628    BEGIN_TEST;
629
630    size_t op_size;
631    fbl::unique_ptr<NandDevice> device = CreateDevice(&op_size);
632    ASSERT_TRUE(device);
633
634    NandTest test;
635    Operation operation(op_size, &test);
636    ASSERT_TRUE(operation.SetDataVmo());
637
638    nand_op_t* op = operation.GetOperation();
639    op->erase.command = NAND_OP_ERASE;
640    op->completion_cb = &NandTest::CompletionCb;
641
642    device->Queue(op);
643    ASSERT_TRUE(test.Wait());
644    ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
645
646    op->erase.first_block = 5;
647    op->erase.num_blocks = 1;
648    device->Queue(op);
649    ASSERT_TRUE(test.Wait());
650    ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
651
652    op->erase.first_block = 4;
653    op->erase.num_blocks = 2;
654    device->Queue(op);
655    ASSERT_TRUE(test.Wait());
656    ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
657
658    END_TEST;
659}
660
661bool EraseTest() {
662    BEGIN_TEST;
663
664    size_t op_size;
665    fbl::unique_ptr<NandDevice> device = CreateDevice(&op_size);
666    ASSERT_TRUE(device);
667
668    NandTest test;
669    Operation operation(op_size, &test);
670
671    nand_op_t* op = operation.GetOperation();
672    op->erase.command = NAND_OP_ERASE;
673    op->erase.first_block = 3;
674    op->erase.num_blocks = 2;
675    op->completion_cb = &NandTest::CompletionCb;
676
677    device->Queue(op);
678    ASSERT_TRUE(test.Wait());
679    ASSERT_EQ(ZX_OK, operation.status());
680
681    memset(op, 0, sizeof(*op));
682    SetForRead(0, kNumPages, &operation);
683    ASSERT_TRUE(operation.SetDataVmo());
684    ASSERT_TRUE(operation.SetOobVmo());
685    op->rw.offset_oob_vmo = kNumPages;
686    device->Queue(op);
687
688    ASSERT_TRUE(test.Wait());
689    ASSERT_EQ(ZX_OK, operation.status());
690    ASSERT_TRUE(CheckPattern(0xff, 0, kNumPages, operation));
691
692    // Verify OOB area.
693    memset(operation.buffer(), 0xff, kOobSize * kNumPages);
694    ASSERT_EQ(0,
695              memcmp(operation.buffer() + kPageSize * kNumPages, operation.buffer(),
696                     kOobSize * kNumPages));
697
698    END_TEST;
699}
700
701}  // namespace
702
703BEGIN_TEST_CASE(RamNandTests)
704RUN_TEST_SMALL(TrivialLifetimeTest)
705RUN_TEST_SMALL(DdkLifetimeTest)
706RUN_TEST_SMALL(BasicDeviceProtocolTest)
707RUN_TEST_SMALL(UnlinkTest)
708RUN_TEST_SMALL(QueryTest)
709RUN_TEST_SMALL(FactoryBadBlockListTest)
710RUN_TEST_SMALL(QueueOneTest)
711RUN_TEST_SMALL(ReadWriteTest)
712RUN_TEST_SMALL(QueueMultipleTest)
713RUN_TEST_SMALL(OobLimitsTest)
714RUN_TEST_SMALL(ReadWriteOobTest)
715RUN_TEST_SMALL(ReadWriteDataAndOobTest)
716RUN_TEST_SMALL(EraseLimitsTest)
717RUN_TEST_SMALL(EraseTest)
718END_TEST_CASE(RamNandTests)
719