Tools for hard drive diagnostics, repair, and data recovery
Post a reply

MiniNVMe and MiniAHCI kernel modules for Linux

September 24th, 2024, 8:07

Hi. Last months I working on interesting project, actually it's a simple disk clone software under the Linux operating system. The main idea is replacing standard NVMe/AHCI drivers to my custom drivers: MiniNVMe and MiniAHCI. As result attached devices will be isolated from the operating system: no mount attempt, no SMART status reading etc. The only way to get access to device is my application. In simple terms - like PC-3000 works.

Whats is I have at this moment? MiniNVMe driver reads some PCI-E (NVMe) device info: PCI id's, link speed, NVMe subsystem version etc. Also PCI-E hot plug supported. Yes, it's not a joke. As you know maybe, PCI-E hot plug supported by the Linux kernel, but to get it work this feature must be also supported by chipset hardware. Not all of the modern PC motherboards support PCI-E hot plug. To control the device's power supply I use a simple CH340 USB relay.

How it looks now?

2024-09-24 21-06-39.png

2024-09-24 17-48-45 11.JPG

2024-09-24 17-49-48 11.JPG

2024-09-24 17-53-00 11.JPG


From time to time I plan to post some news about the project. Not too often I guess. So stay tuned and please share your thoughts below.

Re: Another useless data recovery toy?

September 26th, 2024, 5:57

Oh wow ..

Re: Another useless data recovery toy?

September 27th, 2024, 9:59

following.

Re: Another useless data recovery toy?

October 2nd, 2024, 9:16

Now MiniNVMe driver is able to receive device identification data: model name, firmware revision, serial number, capacity etc. The next step is sectors reading and writing.

2024-10-02 23-08-13.png

Re: Another useless data recovery toy?

October 4th, 2024, 3:20

Very impressive.
I'm following as well.

Re: Another useless data recovery toy?

October 9th, 2024, 3:37

Maybe not that useless :mrgreen:

Re: Another useless data recovery toy?

October 17th, 2024, 8:48

Data transfer is working: read & write.
2024-10-17 22-26-30.png

At this moment my driver does not support software reset sequence. If a patient device does not response (slow responding, firmware background activity, bad block occurred, etc.) the only way to reset it is power replug. I guess in case when mainboard supports PCI-E hot plug it's more than enough.

Re: Another useless data recovery toy?

October 21st, 2024, 10:32

I got a couple of interesting digits: an average read speed from two different devices.
    1. Totally trimmed drive (no real data, returns zeroes only) - 2235.9 MB/ses
    2. Formatted drive, some files dropped - 364.0 MB/sec

Not bad I guess. Especially for self written NVMe device driver for Linux. What do you think?

2024-10-21 23-38-36.png
2024-10-21 23-38-36.png (21.16 KiB) Viewed 61259 times

2024-10-21 23-47-31.png
2024-10-21 23-47-31.png (22.77 KiB) Viewed 61259 times

Re: Another useless data recovery toy?

October 24th, 2024, 8:17

NVMe error codes description in process...
2024-10-24 22-12-13.png

Re: Another useless data recovery toy?

October 24th, 2024, 8:44

aekhv wrote:NVMe error codes description in process...
2024-10-24 22-12-13.png


Those errors do ring a bell ;)

https://www.disktuna.com/decoding-statu ... mart-logs/

Re: Another useless data recovery toy?

October 26th, 2024, 17:37

Wow this is truly becoming a very interesting tool. Following too.

Re: Another useless data recovery toy?

November 21st, 2024, 6:51

Now health info looks like you know what... Ehe-he-he... 8)
2024-11-21 20-46-04.png


Code:
    QNvmeBlockDevice nvme;

    if (!nvme.open("/dev/mininvme0")) {
        ui->plainTextEdit->appendPlainText("Device opening error!");
        return;
    }

    ui->plainTextEdit->appendPlainText("Device /dev/mininvme0 opened...\n");

    QNvmeControllerInfo info = nvme.controllerInfo();
    ui->plainTextEdit->appendPlainText("Model: " + info.modelName());
    ui->plainTextEdit->appendPlainText("Firmware: " + info.firmwareRevision());
    ui->plainTextEdit->appendPlainText("Serial number: " + info.serialNumber());
    ui->plainTextEdit->appendPlainText(QString("Capacity: %1 GB")
                                       .arg(info.totalCapacity() / (1000.0 * 1000.0 * 1000.0), 0, 'f', 1));

    QNvmeLogPageHealthInfo health = nvme.logPageHealthInfo();
    if (!nvme.lastError().success()) {
        ui->plainTextEdit->appendPlainText("Health reading errror!");
        return;
    }

    ui->plainTextEdit->appendPlainText("\n*** HEALTH INFO ***\n");
    ui->plainTextEdit->appendPlainText(QString("Composite temperature: %1 °C")
                                       .arg(health.compositeTemperature() - 273));
    ui->plainTextEdit->appendPlainText(QString("Available spare: %1 %")
                                       .arg(health.availableSpare()));
    ui->plainTextEdit->appendPlainText(QString("Available spare threshold: %1 %")
                                       .arg(health.availableSpareThreshold()));
    ui->plainTextEdit->appendPlainText(QString("Percentage used: %1 %")
                                       .arg(health.percentageUsed()));
    ui->plainTextEdit->appendPlainText(QString("Data units read: %1 (%2 GiB)")
                                       .arg(health.dataUnitsRead()).arg(health.dataUnitsRead() * 512 / (1024 * 1024)));
    ui->plainTextEdit->appendPlainText(QString("Data units written: %1 (%2 GiB)")
                                       .arg(health.dataUnitsWritten()).arg(health.dataUnitsWritten() * 512 / (1024 * 1024)));
    ui->plainTextEdit->appendPlainText(QString("Host read commands: %1")
                                       .arg(health.hostReadCommands()));
    ui->plainTextEdit->appendPlainText(QString("Host write commands: %1")
                                       .arg(health.hostWriteCommands()));
    ui->plainTextEdit->appendPlainText(QString("Controller busy time: %1 m")
                                       .arg(health.controllerBusyTime()));
    ui->plainTextEdit->appendPlainText(QString("Power cycles: %1")
                                       .arg(health.powerCycles()));
    ui->plainTextEdit->appendPlainText(QString("Power on hours: %1")
                                       .arg(health.powerOnHours()));
    ui->plainTextEdit->appendPlainText(QString("Unsafe shutdowns: %1")
                                       .arg(health.unsafeShutdowns()));
    ui->plainTextEdit->appendPlainText(QString("Media and data integrity errors: %1")
                                       .arg(health.mediaAndDataIntegrityErrors()));
    ui->plainTextEdit->appendPlainText(QString("Number of error information log entries: %1")
                                       .arg(health.numberOfErrorInformationLogEntries()));
    ui->plainTextEdit->appendPlainText(QString("Warning composite temperature time: %1 m")
                                       .arg(health.warningCompositeTemperatureTime()));
    ui->plainTextEdit->appendPlainText(QString("Critical composite temperature time: %1 m")
                                       .arg(health.criticalCompositeTemperatureTime()));
    int n = 0;
    foreach (int t, health.temperatureSensors()) {
        n++;
        if (t != 0)
            ui->plainTextEdit->appendPlainText(QString("Temperature sensor #%1: %2 °C").arg(n).arg(t - 273));
        else
            ui->plainTextEdit->appendPlainText(QString("Temperature sensor #%1: no sensor").arg(n));
    }
    ui->plainTextEdit->appendPlainText(QString("Thermal management temperature 1 transition count: %1")
                                       .arg(health.TMT1TransitionCount()));
    ui->plainTextEdit->appendPlainText(QString("Thermal management temperature 2 transition count: %1")
                                       .arg(health.TMT2TransitionCount()));
    ui->plainTextEdit->appendPlainText(QString("Total time for thermal management temperature 1: %1 s")
                                       .arg(health.totalTimeForTMT1()));
    ui->plainTextEdit->appendPlainText(QString("Total time for thermal management temperature 2: %1 s")
                                       .arg(health.totalTimeForTMT2()));

Re: Another useless data recovery toy?

November 21st, 2024, 7:13

Looking good so far.

Would love to see the drive itself on a fly lead outside the case though and positioned so we can get at both sides whilst it's running.

Re: Another useless data recovery toy?

November 21st, 2024, 15:06

Where is the health.criticalWarning attribute?

This is wrong:

Code:
    ui->plainTextEdit->appendPlainText(QString("Data units read: %1 (%2 GiB)")
                                       .arg(health.dataUnitsRead()).arg(health.dataUnitsRead() * 512 / (1024 * 1024)));
    ui->plainTextEdit->appendPlainText(QString("Data units written: %1 (%2 GiB)")
                                       .arg(health.dataUnitsWritten()).arg(health.dataUnitsWritten() * 512 / (1024 * 1024)));

It should be ...

Code:
    ui->plainTextEdit->appendPlainText(QString("Data units read: %1 (%2 GiB)")
                                       .arg(health.dataUnitsRead()).arg(health.dataUnitsRead() * 512 * 1000 / (1024 * 1024 * 1024)));
    ui->plainTextEdit->appendPlainText(QString("Data units written: %1 (%2 GiB)")
                                       .arg(health.dataUnitsWritten()).arg(health.dataUnitsWritten() * 512 * 1000 / (1024 * 1024 * 1024)));

Data Units Read: Contains the number of 512 byte data units the host has read from the controller; this value does not include metadata. This value is reported in thousands (i.e., a value of 1 corresponds to 1,000 units of 512 bytes read) and is rounded up (e.g., one indicates the that number of 512 byte data units read is from 1 to 1,000, three indicates that the number of 512 byte data units read is from 2,001 to 3,000). When the LBA size is a value other than 512 bytes, the controller shall convert the amount of data read to 512 byte units.

Re: Another useless data recovery toy?

November 21st, 2024, 16:23

Lardman wrote:Would love to see the drive itself on a fly lead outside the case though and positioned so we can get at both sides whilst it's running.

Something like this?

https://forum.hddguru.com/viewtopic.php?p=264481#p264481

Re: Another useless data recovery toy?

November 21st, 2024, 23:27

fzabkar wrote:Where is the health.criticalWarning attribute?

Oops, forgot to add...

fzabkar wrote:This is wrong

Yes, I know. I was just curious why the PC-3000 also shows these attributes incorrectly. Obviously this is a mistake.

Re: Another useless data recovery toy?

November 22nd, 2024, 1:18

aekhv wrote:
fzabkar wrote:This is wrong

Yes, I know. I was just curious why the PC-3000 also shows these attributes incorrectly. Obviously this is a mistake.

PC3000 is correct. You are wrong.

https://www.google.com/search?q=0x0a333b+x+512+x+1000+bytes+in+GiB

    0x0a333b x 512 x 1000 bytes = 318.753719 gibibytes

https://www.google.com/search?q=0x09510f+x+512+x+1000+bytes+in+GiB

    0x09510f x 512 x 1000 bytes = 291.144848 gibibytes

Re: Another useless data recovery toy?

November 22nd, 2024, 4:29

fzabkar wrote:PC3000 is correct. You are wrong.

Yeah, it's true. Thanks a lot!

Re: Another useless data recovery toy?

November 22nd, 2024, 5:40

fzabkar wrote:Something like this?

https://forum.hddguru.com/viewtopic.php?p=264481#p264481
More like this https://www.aliexpress.com/item/1005006584734868.html but with the rest of the m2 mounting pcb snapped right back or the the m2 mounted vertically.

We need something that has the drive pcb clear so we can get to both sides and that we can put on an external heater or cooler.

Re: Another useless data recovery toy?

November 22nd, 2024, 14:43

Lardman wrote:
More like this https://www.aliexpress.com/item/1005006584734868.html but with the rest of the m2 mounting pcb snapped right back or the the m2 mounted vertically.

We need something that has the drive pcb clear so we can get to both sides and that we can put on an external heater or cooler.

I'd be wondering about the impedance of the ribbon cable. Mismatches in the impedance would degrade the signal.
Post a reply