File: DtaDevLinuxNvme.cpp

package info (click to toggle)
sedutil 1.20.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,744 kB
  • sloc: cpp: 8,386; xml: 1,433; sh: 810; ansic: 721; makefile: 110
file content (154 lines) | stat: -rwxr-xr-x 4,540 bytes parent folder | download
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
/* C:B**************************************************************************
This software is Copyright 2014-2017 Bright Plaza Inc. <drivetrust@drivetrust.com>

This file is part of sedutil.

sedutil is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

sedutil is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with sedutil.  If not, see <http://www.gnu.org/licenses/>.

 * C:E********************************************************************** */
#include "os.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <scsi/sg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <linux/hdreg.h>
#include <errno.h>
#include <vector>
#include <fstream>
#include "DtaDevLinuxNvme.h"
#include "DtaHexDump.h"

#define  NVME_SECURITY_SEND 0x81
#define  NVME_SECURITY_RECV 0x82
#define  NVME_IDENTIFY 0x06

using namespace std;

/** The Device class represents a single disk device.
 *  Linux specific implementation using the NVMe interface
 */
DtaDevLinuxNvme::DtaDevLinuxNvme() {}

bool DtaDevLinuxNvme::init(const char * devref)
{
    LOG(D1) << "Creating DtaDevLinuxNvme::DtaDev() " << devref;
    ifstream kopts;
    bool isOpen = FALSE;

    if ((fd = open(devref, O_RDWR)) < 0) {
        isOpen = FALSE;
        // This is a D1 because diskscan looks for open fail to end scan
        LOG(D1) << "Error opening device " << devref << " " << (int32_t) fd;
        if (-EPERM == fd) {
            LOG(E) << "You do not have permission to access the raw disk in write mode";
            LOG(E) << "Perhaps you might try sudo to run as root";
        }
    }
    else {
        isOpen = TRUE;
    }
	return isOpen;
}

/** Send an ioctl to the device using nvme admin commands. */
uint8_t DtaDevLinuxNvme::sendCmd(ATACOMMAND cmd, uint8_t protocol, uint16_t comID,
                         void * buffer, uint32_t bufferlen)
{
    struct nvme_admin_cmd nvme_cmd;
	int err;

    LOG(D1) << "Entering DtaDevLinuxNvme::sendCmd";

	memset(&nvme_cmd, 0, sizeof(nvme_cmd));

	if (IF_RECV == cmd) {
		LOG(D3) << "Security Receive Command";
		nvme_cmd.opcode = NVME_SECURITY_RECV;
		nvme_cmd.cdw10 = protocol << 24 | comID << 8;
		nvme_cmd.cdw11 = bufferlen;
		nvme_cmd.data_len = bufferlen;
		nvme_cmd.addr = (__u64)buffer;
	}
	else {
		LOG(D3) << "Security Send Command";
		nvme_cmd.opcode = NVME_SECURITY_SEND;
		nvme_cmd.cdw10 = protocol << 24 | comID << 8;
		nvme_cmd.cdw11 = bufferlen;
		nvme_cmd.data_len = bufferlen;
		nvme_cmd.addr = (__u64)buffer;
	}

	err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &nvme_cmd);
	if (err < 0)
		return errno;
	else if (err != 0) {
		fprintf(stderr, "NVME Security Command Error:%d\n", err);
		IFLOG(D4) DtaHexDump(&nvme_cmd, sizeof(nvme_cmd));
	}
	else
		LOG(D3) << "NVME Security Command Success:" << nvme_cmd.result;
	//LOG(D4) << "NVMe command:";
	//IFLOG(D4) DtaHexDump(&nvme_cmd, sizeof(nvme_cmd));
	//LOG(D4) << "NVMe buffer @ " << buffer;
	//IFLOG(D4) DtaHexDump(buffer, bufferlen);
	return err;
}

void DtaDevLinuxNvme::identify(OPAL_DiskInfo& disk_info)
{
	LOG(D4) << "Entering DtaDevLinuxNvme::identify()";

	struct nvme_admin_cmd cmd;
        uint8_t ctrl[4096];
	int err;

	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = NVME_IDENTIFY;
	cmd.nsid = 0;
	cmd.addr = (unsigned long)&ctrl;
	cmd.data_len = 4096;
	cmd.cdw10 = 1;
	err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);

	if (err) {
		LOG(E) << "Identify error. NVMe status " << err;
		disk_info.devType = DEVICE_TYPE_OTHER;
		IFLOG(D4) DtaHexDump(&cmd, sizeof(cmd));
		IFLOG(D4) DtaHexDump(&ctrl, sizeof(ctrl));
		return;
	}

	disk_info.devType = DEVICE_TYPE_NVME;
	uint8_t *results = ctrl;
	results += 4;
	memcpy(disk_info.serialNum, results, sizeof(disk_info.serialNum));
	results += sizeof(disk_info.serialNum);
	memcpy(disk_info.modelNum, results, sizeof(disk_info.modelNum));
	results += sizeof(disk_info.modelNum);
	memcpy(disk_info.firmwareRev, results, sizeof(disk_info.firmwareRev));


    return;
}

/** Close the device reference so this object can be delete. */
DtaDevLinuxNvme::~DtaDevLinuxNvme()
{
    LOG(D1) << "Destroying DtaDevLinuxNvme";
    close(fd);
}