19#include <sys/drvctlio.h>
20#include <sys/utsname.h>
31#define ARGUSED(x) ((void)(x))
93 fd =
::open(dev,O_RDWR|O_NONBLOCK);
94 if (fd < 0 && errno == EROFS)
95 fd =
::open(dev,O_RDONLY|O_NONBLOCK);
101 if ((fd =
::open(dev,O_RDWR|O_NONBLOCK))<0) {
121 if(failed)
return false;
137 virtual int do_cmd(
struct atareq* request,
bool is_48bit_cmd);
150 ret = ioctl(fd, ATAIOCCOMMAND, request);
157 bool ata_48bit =
false;
164 set_err(ENOSYS,
"48-bit ATA commands not implemented");
169 memset(&req, 0,
sizeof(req));
181 req.flags = ATACMD_READREG;
184 req.flags = ATACMD_READ | ATACMD_READREG;
185 req.databuf = (
char *)in.
buffer;
186 req.datalen = in.
size;
189 req.flags = ATACMD_WRITE | ATACMD_READREG;
190 req.databuf = (
char *)in.
buffer;
191 req.datalen = in.
size;
201 if (req.retsts != ATACMD_OK)
202 return set_err(EIO,
"request failed, error code 0x%02x", req.retsts);
213 for (
int i = 0; i < 256; i+=2)
214 swap2 ((
char *)req.databuf + i);
228 const char * req_type,
unsigned nsid);
230 virtual bool open()
override;
236 const char * req_type,
unsigned nsid)
247 set_err(EINVAL,
"NVMe controller controller/namespace ids must begin with '%s'",
252 int nsid = -1, ctrlid = -1;
255 if(sscanf(dev,
NVME_PREFIX"%d%c", &ctrlid, &tmp) == 1)
258 set_err(EINVAL,
"Invalid NVMe controller number");
264 &ctrlid, &
nsid, &tmp) == 2)
266 if(ctrlid < 0 ||
nsid <= 0) {
267 set_err(EINVAL,
"Invalid NVMe controller/namespace number");
272 set_err(EINVAL,
"Invalid NVMe controller/namespace syntax");
278 snprintf(full_path,
sizeof(full_path),
NVME_PREFIX"%d", ctrlid);
281 if ((fd =
::open(full_path, O_RDWR))<0) {
297 memset(&pt, 0,
sizeof(pt));
314 return set_err(errno,
"NVME_PASSTHROUGH_CMD: %s", strerror(errno));
343 const char * dev_name,
const char * req_type,
bool scanning )
357 const unsigned char * ucp = iop->
cmnd;
361 pout(
" [%s: ", np ? np :
"<unknown opcode>");
363 pout(
"%02x ", ucp[k]);
366 int trunc = (iop->
dxfer_len > 256) ? 1 : 0;
369 (trunc ?
" [only first 256 bytes shown]" :
""));
376 memset(&sc, 0,
sizeof(sc));
379 sc.databuf = (
char *)iop->
dxferp;
387 if (ioctl(fd, SCIOCCOMMAND, &sc) < 0) {
389 pout(
" error sending SCSI ccb\n");
393 iop->
resid = sc.datalen - sc.datalen_used;
396 memcpy(iop->
sensep, sc.sense, sc.senselen_used);
406 (trunc ?
" [only first 256 bytes shown]" :
""));
433 bool sat_only =
false;
444 unsigned char req_buff[64] = {0, };
453 set_err(EIO,
"INQUIRY failed");
458 int avail_len = req_buff[4] + 5;
459 int len = (avail_len < req_len ? avail_len : req_len);
463 set_err(EIO,
"INQUIRY too short for SAT");
483 set_err(EIO,
"Not a SAT device");
500 const char * pattern = 0)
override;
508 unsigned nsid)
override;
527 struct utsname osname;
529 return strprintf(
"%s %s %s", osname.sysname, osname.release, osname.machine);
534 if (!strcmp(appname,
"smartctl")) {
537 p =
'a' + getrawpartition();
539 "=================================================== SMARTCTL EXAMPLES =====\n\n"
540 " smartctl -a /dev/wd0%c (Prints all SMART information)\n\n"
541 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/wd0%c\n"
542 " (Enables SMART on first disk)\n\n"
543 " smartctl -t long /dev/wd0%c (Executes extended disk self-test)\n\n"
544 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/wd0%c\n"
545 " (Prints Self-Test & Attribute errors)\n"
568 char *disknames, *p, **mp;
575 sysctl_mib[0] = CTL_HW;
576 sysctl_mib[1] = HW_DISKNAMES;
577 if (-1 == sysctl(sysctl_mib, 2, NULL, &sysctl_len, NULL, 0)) {
578 pout(
"Failed to get value of sysctl `hw.disknames'\n");
581 if (!(disknames = (
char *)malloc(sysctl_len))) {
582 pout(
"Out of memory constructing scan device list\n");
585 if (-1 == sysctl(sysctl_mib, 2, disknames, &sysctl_len, NULL, 0)) {
586 pout(
"Failed to get value of sysctl `hw.disknames'\n");
589 if (!(mp = (
char **) calloc(strlen(disknames) / 2,
sizeof(
char *)))) {
590 pout(
"Out of memory constructing scan device list\n");
593 for (p = strtok(disknames,
" "); p; p = strtok(NULL,
" ")) {
594 if (strncmp(p, prefix, strlen(prefix))) {
599 pout(
"Out of memory constructing scan device list\n");
612 char ** tmp = (
char **)realloc(mp, n * (
sizeof(
char *)));
614 pout(
"Out of memory constructing scan device list\n");
627 char ctrlpath[64], nspath[64];
629 struct devlistargs laa;
632 int drvfd = ::open(DRVCTLDEV, O_RDONLY, 0);
638 for (
int ctrl = 0;; ctrl++) {
639 snprintf(ctrlpath,
sizeof(ctrlpath),
NVME_PREFIX"%d", ctrl);
640 if (stat(ctrlpath, &sb) == -1 || !S_ISCHR(sb.st_mode))
645 laa.l_childname = NULL;
647 if (ioctl(drvfd, DRVLISTDEV, &laa) == -1) {
658 for (
int nsid = 1; n < laa.l_children;
nsid++) {
661 if (stat(nspath, &sb) == -1 || !S_ISCHR(sb.st_mode))
663 int nsfd = ::open(nspath, O_RDONLY, 0);
680 const char * type,
const char * pattern )
683 set_err(EINVAL,
"DEVICESCAN with pattern not implemented yet");
690 bool scan_ata = !*type || !strcmp(type,
"ata");
691 bool scan_scsi = !*type || !strcmp(type,
"scsi") || !strcmp(type,
"sat");
693#ifdef WITH_NVME_DEVICESCAN
694 bool scan_nvme = !*type || !strcmp(type,
"nvme");
696 bool scan_nvme = !strcmp(type,
"nvme");
700 char * * atanames = 0;
int numata = 0;
709 char * * scsinames = 0;
int numscsi = 0;
710 char * * scsitapenames = 0;
int numscsitape = 0;
718 if (numscsitape < 0) {
726 for (i = 0; i < numata; i++) {
732 if(numata) free(atanames);
734 for (i = 0; i < numscsi; i++) {
740 if(numscsi) free(scsinames);
742 for (i = 0; i < numscsitape; i++) {
746 free(scsitapenames[i]);
748 if(numscsitape) free(scsitapenames);
758 const char * test_name = name;
767 if (!lstat(name, &st) && S_ISLNK(st.st_mode)) {
768 char * p = realpath(name, (
char *)0);
772 test_name = pathbuf.c_str();
void swap2(char *location)
#define ATA_IDENTIFY_DEVICE
bool ata_cmd_is_ok(const ata_cmd_in &in, bool data_out_support=false, bool multi_sector_support=false, bool ata_48bit_support=false)
Check command input parameters (old version).
unsigned get_nsid() const
Get namespace id.
bool set_nvme_err(nvme_cmd_out &out, unsigned status, const char *msg=0)
Set last error number and message if pass-through returns NVMe error status.
void set_nsid(unsigned nsid)
Set namespace id.
Implement standard ATA support.
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out) override
ATA pass through.
virtual int do_cmd(struct atareq *request, bool is_48bit_cmd)
netbsd_ata_device(smart_interface *intf, const char *dev_name, const char *req_type)
virtual bool nvme_pass_through(const nvme_cmd_in &in, nvme_cmd_out &out) override
NVMe pass through.
netbsd_nvme_device(smart_interface *intf, const char *dev_name, const char *req_type, unsigned nsid)
virtual bool open() override
Open device, return false on error.
virtual smart_device * autodetect_open() override
Open device with autodetection support.
netbsd_scsi_device(smart_interface *intf, const char *dev_name, const char *req_type, bool scanning=false)
virtual bool scsi_pass_through(scsi_cmnd_io *iop) override
SCSI pass through.
bool m_scanning
true if created within scan_smart_devices
Implement shared open/close routines with old functions.
virtual bool is_open() const
Return true if device is open.
virtual ~netbsd_smart_device()
int m_fd
filedesc, -1 if not open.
virtual bool close()
Close device, return false on error.
virtual bool open()
Open device, return false on error.
int get_fd() const
Return filedesc for derived classes.
Implement platform interface with old functions.
virtual bool scan_smart_devices(smart_device_list &devlist, const char *type, const char *pattern=0) override
Fill 'devlist' with devices of some 'type' with device names specified by some optional 'pattern'.
virtual smart_device * autodetect_smart_device(const char *name) override
Autodetect device if no device type specified.
int get_dev_names(char ***, const char *)
virtual scsi_device * get_scsi_device(const char *name, const char *type) override
Return standard SCSI device.
virtual std::string get_app_examples(const char *appname) override
Return example string for program 'appname'.
bool get_nvme_devlist(smart_device_list &devlist, const char *type)
virtual std::string get_os_version_str() override
Return info string about build host and/or OS version.
virtual ata_device * get_ata_device(const char *name, const char *type) override
Return standard ATA device.
virtual smart_device * get_custom_smart_device(const char *name, const char *type) override
Return device for platform specific 'type'.
virtual std::string get_valid_custom_dev_types_str() override
Return valid 'type' args accepted by above.
virtual nvme_device * get_nvme_device(const char *name, const char *type, unsigned nsid) override
Return standard NVMe device.
List of devices for DEVICESCAN.
void push_back(smart_device *dev)
Base class for all devices.
bool is_scsi() const
Return true if SCSI device.
bool is_nvme() const
Return true if NVMe device.
smart_interface * smi()
Get interface which produced this object.
const char * get_req_type() const
Get type requested by user, empty if none.
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
bool is_ata() const
Return true if ATA device.
const char * get_dev_name() const
Get device (path)name.
void clear_err()
Clear last error info.
The platform interface abstraction.
static void set(smart_interface *intf)
Set interface to use, must be called from init().
static void init()
Initialize platform interface and register with smi().
virtual ata_device * autodetect_sat_device(scsi_device *scsidev, const unsigned char *inqdata, unsigned inqsize)
Try to detect a SAT device behind a SCSI interface.
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
#define NVME_PASSTHROUGH_CMD
#define nvme_completion_is_error(cpl)
static const char * net_dev_scsi_disk
static const char * net_dev_nvme_ctrl
static const char * net_dev_raw_prefix
static const char * net_dev_ata_disk
static const char * net_dev_prefix
static const char * net_dev_scsi_tape
const char * os_netbsd_cpp_cvsid
#define OS_NETBSD_H_CVSID
int scsiStdInquiry(scsi_device *device, uint8_t *pBuf, int bufLen)
void dStrHex(const uint8_t *up, int len, int no_ascii)
unsigned char scsi_debugmode
const char * scsi_get_opcode_name(const uint8_t *cdbp)
#define DXFER_FROM_DEVICE
#define SCSI_TIMEOUT_DEFAULT
void pout(const char *fmt,...)
ATA pass through input parameters.
enum ata_cmd_in::@29 direction
I/O direction.
void * buffer
Pointer to data buffer.
ata_in_regs_48bit in_regs
Input registers.
unsigned size
Size of buffer.
ATA pass through output parameters.
ata_out_regs_48bit out_regs
Output registers.
bool is_48bit_cmd() const
Return true if 48-bit command.
ata_register sector_count
ata_register sector_count
NVMe pass through input parameters.
unsigned char opcode
Opcode (CDW0 07:00)
unsigned size
Size of buffer.
unsigned cdw15
Cmd specific.
unsigned nsid
Namespace ID.
void * buffer
Pointer to data buffer.
NVMe pass through output parameters.
unsigned result
Command specific result (DW0)
struct nvme_completion cpl
std::string strprintf(const char *fmt,...)
bool str_starts_with(const char *str, const char *prefix)