4 * Home page of code is: http://smartmontools.sourceforge.net
6 * Copyright (C) 2004-6 David Snyder <smartmontools-support@lists.sourceforge.net>
8 * Derived from os_netbsd.cpp by Sergey Svishchev <smartmontools-support@lists.sourceforge.net>, Copyright (C) 2003-6
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
15 * You should have received a copy of the GNU General Public License
16 * (for example COPYING); if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "os_openbsd.h"
28 const char *os_XXXX_c_cvsid
= "$Id: os_openbsd.cpp,v 1.13 2006/09/20 16:17:31 shattered Exp $" \
29 ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_OPENBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID
;
31 /* global variable holding byte count of allocated memory */
32 extern long long bytes
;
35 BAD_SMART
, NO_3WARE
, MAX_MSG
38 /* Utility function for printing warnings */
40 printwarning(int msgNo
, const char *extra
)
42 static int printed
[] = {0, 0};
43 static const char *message
[] = {
44 "Error: SMART Status command failed.\nPlease get assistance from \n" PACKAGE_HOMEPAGE
"\nRegister values returned from SMART Status command are:\n",
45 PACKAGE_STRING
" does not currentlly support twe(4) devices (3ware Escalade)\n",
48 if (msgNo
>= 0 && msgNo
<= MAX_MSG
) {
49 if (!printed
[msgNo
]) {
51 pout("%s", message
[msgNo
]);
59 static const char *net_dev_prefix
= "/dev/";
60 static const char *net_dev_ata_disk
= "wd";
61 static const char *net_dev_scsi_disk
= "sd";
62 static const char *net_dev_scsi_tape
= "st";
64 /* Guess device type(ata or scsi) based on device name */
66 guess_device_type(const char *dev_name
)
69 int dev_prefix_len
= strlen(net_dev_prefix
);
71 if (!dev_name
|| !(len
= strlen(dev_name
)))
72 return CONTROLLER_UNKNOWN
;
74 if (!strncmp(net_dev_prefix
, dev_name
, dev_prefix_len
)) {
75 if (len
<= dev_prefix_len
)
76 return CONTROLLER_UNKNOWN
;
78 dev_name
+= dev_prefix_len
;
80 if (!strncmp(net_dev_ata_disk
, dev_name
, strlen(net_dev_ata_disk
)))
81 return CONTROLLER_ATA
;
83 if (!strncmp(net_dev_scsi_disk
, dev_name
, strlen(net_dev_scsi_disk
)))
84 return CONTROLLER_SCSI
;
86 if (!strncmp(net_dev_scsi_tape
, dev_name
, strlen(net_dev_scsi_tape
)))
87 return CONTROLLER_SCSI
;
89 return CONTROLLER_UNKNOWN
;
93 get_dev_names(char ***names
, const char *prefix
)
95 char *disknames
, *p
, **mp
;
102 sysctl_mib
[0] = CTL_HW
;
103 sysctl_mib
[1] = HW_DISKNAMES
;
104 if (-1 == sysctl(sysctl_mib
, 2, NULL
, &sysctl_len
, NULL
, 0)) {
105 pout("Failed to get value of sysctl `hw.disknames'\n");
108 if (!(disknames
= (char*)malloc(sysctl_len
))) {
109 pout("Out of memory constructing scan device list\n");
112 if (-1 == sysctl(sysctl_mib
, 2, disknames
, &sysctl_len
, NULL
, 0)) {
113 pout("Failed to get value of sysctl `hw.disknames'\n");
116 if (!(mp
= (char **) calloc(strlen(disknames
) / 2, sizeof(char *)))) {
117 pout("Out of memory constructing scan device list\n");
120 for (p
= strtok(disknames
, ","); p
; p
= strtok(NULL
, ",")) {
121 if (strncmp(p
, prefix
, strlen(prefix
))) {
124 mp
[n
] = (char*)malloc(strlen(net_dev_prefix
) + strlen(p
) + 2);
126 pout("Out of memory constructing scan device list\n");
129 sprintf(mp
[n
], "%s%s%c", net_dev_prefix
, p
, 'a' + getrawpartition());
130 bytes
+= strlen(mp
[n
]) + 1;
134 mp
= (char**)realloc(mp
, n
* (sizeof(char *)));
135 bytes
+= (n
) * (sizeof(char *));
141 make_device_names(char ***devlist
, const char *name
)
143 if (!strcmp(name
, "SCSI"))
144 return get_dev_names(devlist
, net_dev_scsi_disk
);
145 else if (!strcmp(name
, "ATA"))
146 return get_dev_names(devlist
, net_dev_ata_disk
);
152 deviceopen(const char *pathname
, char *type
)
154 if (!strcmp(type
, "SCSI")) {
155 int fd
= open(pathname
, O_RDWR
| O_NONBLOCK
);
156 if (fd
< 0 && errno
== EROFS
)
157 fd
= open(pathname
, O_RDONLY
| O_NONBLOCK
);
159 } else if (!strcmp(type
, "ATA"))
160 return open(pathname
, O_RDWR
| O_NONBLOCK
);
172 marvell_command_interface(int fd
, smart_command_set command
, int select
, char *data
)
175 int highpoint_command_interface(int fd
, smart_command_set command
, int select
, char *data
)
181 ata_command_interface(int fd
, smart_command_set command
, int select
, char *data
)
184 unsigned char inbuf
[DEV_BSIZE
];
185 int retval
, copydata
= 0;
187 memset(&req
, 0, sizeof(req
));
188 memset(&inbuf
, 0, sizeof(inbuf
));
192 req
.flags
= ATACMD_READ
;
193 req
.features
= ATA_SMART_READ_VALUES
;
194 req
.command
= ATAPI_SMART
;
195 req
.databuf
= (caddr_t
) inbuf
;
196 req
.datalen
= sizeof(inbuf
);
197 req
.cylinder
= htole16(WDSMART_CYL
);
201 case READ_THRESHOLDS
:
202 req
.flags
= ATACMD_READ
;
203 req
.features
= ATA_SMART_READ_THRESHOLDS
;
204 req
.command
= ATAPI_SMART
;
205 req
.databuf
= (caddr_t
) inbuf
;
206 req
.datalen
= sizeof(inbuf
);
207 req
.cylinder
= htole16(WDSMART_CYL
);
212 req
.flags
= ATACMD_READ
;
213 req
.features
= ATA_SMART_READ_LOG_SECTOR
; /* XXX missing from wdcreg.h */
214 req
.command
= ATAPI_SMART
;
215 req
.databuf
= (caddr_t
) inbuf
;
216 req
.datalen
= sizeof(inbuf
);
217 req
.cylinder
= htole16(WDSMART_CYL
);
218 req
.sec_num
= select
;
224 memcpy(inbuf
, data
, 512);
225 req
.flags
= ATACMD_WRITE
;
226 req
.features
= ATA_SMART_WRITE_LOG_SECTOR
; /* XXX missing from wdcreg.h */
227 req
.command
= ATAPI_SMART
;
228 req
.databuf
= (caddr_t
) inbuf
;
229 req
.datalen
= sizeof(inbuf
);
230 req
.cylinder
= htole16(WDSMART_CYL
);
231 req
.sec_num
= select
;
236 req
.flags
= ATACMD_READ
;
237 req
.command
= WDCC_IDENTIFY
;
238 req
.databuf
= (caddr_t
) inbuf
;
239 req
.datalen
= sizeof(inbuf
);
244 req
.flags
= ATACMD_READ
;
245 req
.command
= ATAPI_IDENTIFY_DEVICE
;
246 req
.databuf
= (caddr_t
) inbuf
;
247 req
.datalen
= sizeof(inbuf
);
252 req
.flags
= ATACMD_READ
;
253 req
.features
= ATA_SMART_ENABLE
;
254 req
.command
= ATAPI_SMART
;
255 req
.cylinder
= htole16(WDSMART_CYL
);
259 req
.flags
= ATACMD_READ
;
260 req
.features
= ATA_SMART_DISABLE
;
261 req
.command
= ATAPI_SMART
;
262 req
.cylinder
= htole16(WDSMART_CYL
);
266 /* NOTE: According to ATAPI 4 and UP, this command is obsolete */
267 req
.flags
= ATACMD_READ
;
268 req
.features
= ATA_SMART_AUTO_OFFLINE
; /* XXX missing from wdcreg.h */
269 req
.command
= ATAPI_SMART
;
270 req
.databuf
= (caddr_t
) inbuf
;
271 req
.datalen
= sizeof(inbuf
);
272 req
.cylinder
= htole16(WDSMART_CYL
);
273 req
.sec_num
= select
;
278 req
.flags
= ATACMD_READ
;
279 req
.features
= ATA_SMART_AUTOSAVE
; /* XXX missing from wdcreg.h */
280 req
.command
= ATAPI_SMART
;
281 req
.cylinder
= htole16(WDSMART_CYL
);
282 req
.sec_count
= 0xf1;
283 /* to enable autosave */
286 case IMMEDIATE_OFFLINE
:
287 /* NOTE: According to ATAPI 4 and UP, this command is obsolete */
288 req
.flags
= ATACMD_READ
;
289 req
.features
= ATA_SMART_IMMEDIATE_OFFLINE
; /* XXX missing from wdcreg.h */
290 req
.command
= ATAPI_SMART
;
291 req
.databuf
= (caddr_t
) inbuf
;
292 req
.datalen
= sizeof(inbuf
);
293 req
.cylinder
= htole16(WDSMART_CYL
);
294 req
.sec_num
= select
;
299 /* same command, no HDIO in NetBSD */
301 req
.flags
= ATACMD_READ
;
302 req
.features
= ATA_SMART_STATUS
;
303 req
.command
= ATAPI_SMART
;
304 req
.cylinder
= htole16(WDSMART_CYL
);
307 case CHECK_POWER_MODE
:
308 req
.flags
= ATACMD_READREG
;
309 req
.command
= WDCC_CHECK_PWR
;
313 pout("Unrecognized command %d in ata_command_interface()\n", command
);
318 if (command
== STATUS_CHECK
) {
321 unsigned const short normal
= WDSMART_CYL
, failed
= 0x2cf4;
323 if ((retval
= ioctl(fd
, ATAIOCCOMMAND
, &req
))) {
324 perror("Failed command");
327 /* Cyl low and Cyl high unchanged means "Good SMART status" */
328 if (letoh16(req
.cylinder
) == normal
)
331 /* These values mean "Bad SMART status" */
332 if (letoh16(req
.cylinder
) == failed
)
335 /* We haven't gotten output that makes sense;
336 * print out some debugging info */
337 snprintf(buf
, sizeof(buf
),
338 "CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
339 (int) req
.command
, (int) req
.features
, (int) req
.sec_count
, (int) req
.sec_num
,
340 (int) (letoh16(req
.cylinder
) & 0xff), (int) ((letoh16(req
.cylinder
) >> 8) & 0xff),
342 printwarning(BAD_SMART
, buf
);
345 if ((retval
= ioctl(fd
, ATAIOCCOMMAND
, &req
))) {
346 perror("Failed command");
349 if (command
== CHECK_POWER_MODE
)
350 data
[0] = req
.sec_count
;
353 memcpy(data
, inbuf
, 512);
359 escalade_command_interface(int fd
, int disknum
, int escalade_type
, smart_command_set command
, int select
, char *data
)
361 printwarning(NO_3WARE
, NULL
);
366 do_scsi_cmnd_io(int fd
, struct scsi_cmnd_io
* iop
, int report
)
373 const unsigned char *ucp
= iop
->cmnd
;
376 np
= scsi_get_opcode_name(ucp
[0]);
377 pout(" [%s: ", np
? np
: "<unknown opcode>");
378 for (k
= 0; k
< iop
->cmnd_len
; ++k
)
379 pout("%02x ", ucp
[k
]);
381 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
382 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
384 pout("]\n Outgoing data, len=%d%s:\n", (int) iop
->dxfer_len
,
385 (trunc
? " [only first 256 bytes shown]" : ""));
386 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
), 1);
390 memset(&sc
, 0, sizeof(sc
));
391 memcpy(sc
.cmd
, iop
->cmnd
, iop
->cmnd_len
);
392 sc
.cmdlen
= iop
->cmnd_len
;
393 sc
.databuf
= (char*)iop
->dxferp
;
394 sc
.datalen
= iop
->dxfer_len
;
395 sc
.senselen
= iop
->max_sense_len
;
396 sc
.timeout
= iop
->timeout
== 0 ? 60000 : iop
->timeout
; /* XXX */
398 (iop
->dxfer_dir
== DXFER_NONE
? SCCMD_READ
: /* XXX */
399 (iop
->dxfer_dir
== DXFER_FROM_DEVICE
? SCCMD_READ
: SCCMD_WRITE
));
401 if (ioctl(fd
, SCIOCCOMMAND
, &sc
) < 0) {
402 warn("error sending SCSI ccb");
405 iop
->resid
= sc
.datalen
- sc
.datalen_used
;
406 iop
->scsi_status
= sc
.status
;
408 memcpy(iop
->sensep
, sc
.sense
, sc
.senselen_used
);
409 iop
->resp_sense_len
= sc
.senselen_used
;
415 trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
417 pout(" Incoming data, len=%d%s:\n", (int) iop
->dxfer_len
,
418 (trunc
? " [only first 256 bytes shown]" : ""));
419 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
), 1);
424 /* print examples for smartctl */
426 print_smartctl_examples()
430 p
= 'a' + getrawpartition();
431 printf("=================================================== SMARTCTL EXAMPLES =====\n\n");
432 #ifdef HAVE_GETOPT_LONG
434 " smartctl -a /dev/wd0%c (Prints all SMART information)\n\n"
435 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/wd0%c\n"
436 " (Enables SMART on first disk)\n\n"
437 " smartctl -t long /dev/wd0%c (Executes extended disk self-test)\n\n"
438 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/wd0%c\n"
439 " (Prints Self-Test & Attribute errors)\n",
444 " smartctl -a /dev/wd0%c (Prints all SMART information)\n"
445 " smartctl -s on -o on -S on /dev/wd0%c (Enables SMART on first disk)\n"
446 " smartctl -t long /dev/wd0%c (Executes extended disk self-test)\n"
447 " smartctl -A -l selftest -q errorsonly /dev/wd0%c"
448 " (Prints Self-Test & Attribute errors)\n",