4 * Home page of code is: http://www.smartmontools.org
6 * Copyright (C) 2003-8 Sergey Svishchev <smartmontools-support@lists.sourceforge.net>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
13 * You should have received a copy of the GNU General Public License
14 * (for example COPYING); if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "os_netbsd.h"
29 const char * os_netbsd_cpp_cvsid
= "$Id: os_netbsd.cpp 4320 2016-05-10 13:39:19Z chrfranke $"
36 /* Utility function for printing warnings */
38 printwarning(int msgNo
, const char *extra
)
40 static int printed
[] = {0, 0};
41 static const char *message
[] = {
42 "Error: SMART Status command failed.\nPlease get assistance from \n" PACKAGE_HOMEPAGE
"\nRegister values returned from SMART Status command are:\n",
43 PACKAGE_STRING
" does not currently support twe(4) and twa(4) devices (3ware Escalade, Apache)\n",
46 if (msgNo
>= 0 && msgNo
<= MAX_MSG
) {
47 if (!printed
[msgNo
]) {
49 pout("%s", message
[msgNo
]);
57 static const char *net_dev_prefix
= "/dev/r";
58 static const char *net_dev_ata_disk
= "wd";
59 static const char *net_dev_scsi_disk
= "sd";
60 static const char *net_dev_scsi_tape
= "enrst";
62 /* Guess device type (ATA or SCSI) based on device name */
64 guess_device_type(const char *dev_name
)
67 int dev_prefix_len
= strlen(net_dev_prefix
);
69 if (!dev_name
|| !(len
= strlen(dev_name
)))
70 return CONTROLLER_UNKNOWN
;
72 if (!strncmp(net_dev_prefix
, dev_name
, dev_prefix_len
)) {
73 if (len
<= dev_prefix_len
)
74 return CONTROLLER_UNKNOWN
;
76 dev_name
+= dev_prefix_len
;
78 if (!strncmp(net_dev_ata_disk
, dev_name
, strlen(net_dev_ata_disk
)))
79 return CONTROLLER_ATA
;
81 if (!strncmp(net_dev_scsi_disk
, dev_name
, strlen(net_dev_scsi_disk
)))
82 return CONTROLLER_SCSI
;
84 if (!strncmp(net_dev_scsi_tape
, dev_name
, strlen(net_dev_scsi_tape
)))
85 return CONTROLLER_SCSI
;
87 return CONTROLLER_UNKNOWN
;
91 get_dev_names(char ***names
, const char *prefix
)
93 char *disknames
, *p
, **mp
;
100 sysctl_mib
[0] = CTL_HW
;
101 sysctl_mib
[1] = HW_DISKNAMES
;
102 if (-1 == sysctl(sysctl_mib
, 2, NULL
, &sysctl_len
, NULL
, 0)) {
103 pout("Failed to get value of sysctl `hw.disknames'\n");
106 if (!(disknames
= (char *)malloc(sysctl_len
))) {
107 pout("Out of memory constructing scan device list\n");
110 if (-1 == sysctl(sysctl_mib
, 2, disknames
, &sysctl_len
, NULL
, 0)) {
111 pout("Failed to get value of sysctl `hw.disknames'\n");
114 if (!(mp
= (char **) calloc(strlen(disknames
) / 2, sizeof(char *)))) {
115 pout("Out of memory constructing scan device list\n");
118 for (p
= strtok(disknames
, " "); p
; p
= strtok(NULL
, " ")) {
119 if (strncmp(p
, prefix
, strlen(prefix
))) {
122 mp
[n
] = (char *)malloc(strlen(net_dev_prefix
) + strlen(p
) + 2);
124 pout("Out of memory constructing scan device list\n");
127 sprintf(mp
[n
], "%s%s%c", net_dev_prefix
, p
, 'a' + getrawpartition());
131 char ** tmp
= (char **)realloc(mp
, n
* (sizeof(char *)));
133 pout("Out of memory constructing scan device list\n");
144 make_device_names(char ***devlist
, const char *name
)
146 if (!strcmp(name
, "SCSI"))
147 return get_dev_names(devlist
, net_dev_scsi_disk
);
148 else if (!strcmp(name
, "ATA"))
149 return get_dev_names(devlist
, net_dev_ata_disk
);
155 deviceopen(const char *pathname
, char *type
)
157 if (!strcmp(type
, "SCSI")) {
158 int fd
= open(pathname
, O_RDWR
| O_NONBLOCK
);
159 if (fd
< 0 && errno
== EROFS
)
160 fd
= open(pathname
, O_RDONLY
| O_NONBLOCK
);
162 } else if (!strcmp(type
, "ATA"))
163 return open(pathname
, O_RDWR
| O_NONBLOCK
);
175 ata_command_interface(int fd
, smart_command_set command
, int select
, char *data
)
178 unsigned char inbuf
[DEV_BSIZE
];
179 int retval
, copydata
= 0;
181 memset(&req
, 0, sizeof(req
));
184 memset(&inbuf
, 0, sizeof(inbuf
));
188 req
.flags
= ATACMD_READ
;
189 req
.features
= WDSM_RD_DATA
;
190 req
.command
= WDCC_SMART
;
191 req
.databuf
= (char *)inbuf
;
192 req
.datalen
= sizeof(inbuf
);
193 req
.cylinder
= WDSMART_CYL
;
196 case READ_THRESHOLDS
:
197 req
.flags
= ATACMD_READ
;
198 req
.features
= WDSM_RD_THRESHOLDS
;
199 req
.command
= WDCC_SMART
;
200 req
.databuf
= (char *)inbuf
;
201 req
.datalen
= sizeof(inbuf
);
202 req
.cylinder
= WDSMART_CYL
;
206 req
.flags
= ATACMD_READ
;
207 req
.features
= ATA_SMART_READ_LOG_SECTOR
; /* XXX missing from wdcreg.h */
208 req
.command
= WDCC_SMART
;
209 req
.databuf
= (char *)inbuf
;
210 req
.datalen
= sizeof(inbuf
);
211 req
.cylinder
= WDSMART_CYL
;
212 req
.sec_num
= select
;
217 memcpy(inbuf
, data
, 512);
218 req
.flags
= ATACMD_WRITE
;
219 req
.features
= ATA_SMART_WRITE_LOG_SECTOR
; /* XXX missing from wdcreg.h */
220 req
.command
= WDCC_SMART
;
221 req
.databuf
= (char *)inbuf
;
222 req
.datalen
= sizeof(inbuf
);
223 req
.cylinder
= WDSMART_CYL
;
224 req
.sec_num
= select
;
228 req
.flags
= ATACMD_READ
;
229 req
.command
= WDCC_IDENTIFY
;
230 req
.databuf
= (char *)inbuf
;
231 req
.datalen
= sizeof(inbuf
);
235 req
.flags
= ATACMD_READ
;
236 req
.command
= ATAPI_IDENTIFY_DEVICE
;
237 req
.databuf
= (char *)inbuf
;
238 req
.datalen
= sizeof(inbuf
);
242 req
.flags
= ATACMD_READREG
;
243 req
.features
= WDSM_ENABLE_OPS
;
244 req
.command
= WDCC_SMART
;
245 req
.cylinder
= WDSMART_CYL
;
248 req
.flags
= ATACMD_READREG
;
249 req
.features
= WDSM_DISABLE_OPS
;
250 req
.command
= WDCC_SMART
;
251 req
.cylinder
= WDSMART_CYL
;
254 /* NOTE: According to ATAPI 4 and UP, this command is obsolete */
255 req
.flags
= ATACMD_READREG
;
256 req
.features
= ATA_SMART_AUTO_OFFLINE
; /* XXX missing from wdcreg.h */
257 req
.command
= WDCC_SMART
;
258 req
.cylinder
= WDSMART_CYL
;
259 req
.sec_count
= select
;
262 req
.flags
= ATACMD_READREG
;
263 req
.features
= ATA_SMART_AUTOSAVE
; /* XXX missing from wdcreg.h */
264 req
.command
= WDCC_SMART
;
265 req
.cylinder
= WDSMART_CYL
;
266 req
.sec_count
= select
;
268 case IMMEDIATE_OFFLINE
:
269 /* NOTE: According to ATAPI 4 and UP, this command is obsolete */
270 req
.flags
= ATACMD_READREG
;
271 req
.features
= ATA_SMART_IMMEDIATE_OFFLINE
; /* XXX missing from wdcreg.h */
272 req
.command
= WDCC_SMART
;
273 req
.cylinder
= WDSMART_CYL
;
274 req
.sec_num
= select
;
277 case STATUS
: /* should return 0 if SMART is enabled at all */
278 case STATUS_CHECK
: /* should return 0 if disk's health is ok */
279 req
.flags
= ATACMD_READREG
;
280 req
.features
= WDSM_STATUS
;
281 req
.command
= WDCC_SMART
;
282 req
.cylinder
= WDSMART_CYL
;
284 case CHECK_POWER_MODE
:
285 req
.flags
= ATACMD_READREG
;
286 req
.command
= WDCC_CHECK_PWR
;
289 pout("Unrecognized command %d in ata_command_interface()\n", command
);
294 if (command
== STATUS_CHECK
|| command
== AUTOSAVE
|| command
== AUTO_OFFLINE
) {
297 unsigned const short normal
= WDSMART_CYL
, failed
= 0x2cf4;
299 if ((retval
= ioctl(fd
, ATAIOCCOMMAND
, &req
))) {
300 perror("Failed command");
303 if (req
.retsts
!= ATACMD_OK
) {
306 /* Cyl low and Cyl high unchanged means "Good SMART status" */
307 if (req
.cylinder
== normal
)
310 /* These values mean "Bad SMART status" */
311 if (req
.cylinder
== failed
)
314 /* We haven't gotten output that makes sense;
315 * print out some debugging info */
316 snprintf(buf
, sizeof(buf
),
317 "CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
318 (int) req
.command
, (int) req
.features
, (int) req
.sec_count
, (int) req
.sec_num
,
319 (int) (le16toh(req
.cylinder
) & 0xff), (int) ((le16toh(req
.cylinder
) >> 8) & 0xff),
321 printwarning(BAD_SMART
, buf
);
325 retval
= ioctl(fd
, ATAIOCCOMMAND
, &req
);
327 perror("Failed command");
330 if (req
.retsts
!= ATACMD_OK
) {
334 if (command
== CHECK_POWER_MODE
)
335 data
[0] = req
.sec_count
;
338 memcpy(data
, inbuf
, 512);
344 do_scsi_cmnd_io(int fd
, struct scsi_cmnd_io
* iop
, int report
)
351 const unsigned char *ucp
= iop
->cmnd
;
354 np
= scsi_get_opcode_name(ucp
[0]);
355 pout(" [%s: ", np
? np
: "<unknown opcode>");
356 for (k
= 0; k
< iop
->cmnd_len
; ++k
)
357 pout("%02x ", ucp
[k
]);
359 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
360 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
362 pout("]\n Outgoing data, len=%d%s:\n", (int) iop
->dxfer_len
,
363 (trunc
? " [only first 256 bytes shown]" : ""));
364 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
), 1);
368 memset(&sc
, 0, sizeof(sc
));
369 memcpy(sc
.cmd
, iop
->cmnd
, iop
->cmnd_len
);
370 sc
.cmdlen
= iop
->cmnd_len
;
371 sc
.databuf
= (char *)iop
->dxferp
;
372 sc
.datalen
= iop
->dxfer_len
;
373 sc
.senselen
= iop
->max_sense_len
;
374 sc
.timeout
= iop
->timeout
== 0 ? 60000 : (1000 * iop
->timeout
);
376 (iop
->dxfer_dir
== DXFER_NONE
? SCCMD_READ
:
377 (iop
->dxfer_dir
== DXFER_FROM_DEVICE
? SCCMD_READ
: SCCMD_WRITE
));
379 if (ioctl(fd
, SCIOCCOMMAND
, &sc
) < 0) {
380 warn("error sending SCSI ccb");
383 iop
->resid
= sc
.datalen
- sc
.datalen_used
;
384 iop
->scsi_status
= sc
.status
;
386 memcpy(iop
->sensep
, sc
.sense
, sc
.senselen_used
);
387 iop
->resp_sense_len
= sc
.senselen_used
;
393 trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
395 pout(" Incoming data, len=%d%s:\n", (int) iop
->dxfer_len
,
396 (trunc
? " [only first 256 bytes shown]" : ""));
397 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
), 1);
411 /* print examples for smartctl */
413 print_smartctl_examples()
417 p
= 'a' + getrawpartition();
418 printf("=================================================== SMARTCTL EXAMPLES =====\n\n");
419 #ifdef HAVE_GETOPT_LONG
421 " smartctl -a /dev/wd0%c (Prints all SMART information)\n\n"
422 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/wd0%c\n"
423 " (Enables SMART on first disk)\n\n"
424 " smartctl -t long /dev/wd0%c (Executes extended disk self-test)\n\n"
425 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/wd0%c\n"
426 " (Prints Self-Test & Attribute errors)\n",
431 " smartctl -a /dev/wd0%c (Prints all SMART information)\n"
432 " smartctl -s on -o on -S on /dev/wd0%c (Enables SMART on first disk)\n"
433 " smartctl -t long /dev/wd0%c (Executes extended disk self-test)\n"
434 " smartctl -A -l selftest -q errorsonly /dev/wd0%c"
435 " (Prints Self-Test & Attribute errors)\n",