4 * Home page of code is: http://smartmontools.sourceforge.net
6 * Copyright (C) 2003-8 SAWADA Keiji <smartmontools-support@lists.sourceforge.net>
7 * Copyright (C) 2003-8 Casper Dik <smartmontools-support@lists.sourceforge.net>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
14 * You should have received a copy of the GNU General Public License
15 * (for example COPYING); if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include <sys/param.h>
28 // These are needed to define prototypes for the functions defined below
35 // This is to include whatever prototypes you define in os_solaris.h
36 #include "os_solaris.h"
38 #define ARGUSED(x) ((void)(x))
40 extern long long bytes
;
42 static const char *filenameandversion
="$Id: os_solaris.cpp 3806 2013-03-29 20:17:03Z chrfranke $";
44 const char *os_XXXX_c_cvsid
="$Id: os_solaris.cpp 3806 2013-03-29 20:17:03Z chrfranke $" \
45 ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_SOLARIS_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID
;
47 // The printwarning() function warns about unimplemented functions
49 char *unimplemented
[2]={
50 "ATA command routine ata_command_interface()",
51 "3ware Escalade Controller command routine escalade_command_interface()",
54 int printwarning(int which
){
55 if (!unimplemented
[which
])
58 if (printedout
[which
])
64 "#######################################################################\n"
65 "%s NOT IMPLEMENTED under Solaris.\n"
66 "Please contact " PACKAGE_BUGREPORT
" if\n"
67 "you want to help in porting smartmontools to Solaris.\n"
68 "#######################################################################\n"
70 unimplemented
[which
]);
75 // print examples for smartctl
76 void print_smartctl_examples(){
77 printf("=================================================== SMARTCTL EXAMPLES =====\n\n");
78 #ifdef HAVE_GETOPT_LONG
80 " smartctl -a /dev/rdsk/c0t0d0s0 (Prints all SMART information)\n\n"
81 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/rdsk/c0t0d0s0\n"
82 " (Enables SMART on first disk)\n\n"
83 " smartctl -t long /dev/rdsk/c0t0d0s0 (Executes extended disk self-test)\n\n"
84 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/rdsk/c0t0d0s0\n"
85 " (Prints Self-Test & Attribute errors)\n"
89 " smartctl -a /dev/rdsk/c0t0d0s0 (Prints all SMART information)\n"
90 " smartctl -s on -o on -S on /dev/rdsk/c0t0d0s0 (Enables SMART on first disk)\n"
91 " smartctl -t long /dev/rdsk/c0t0d0s0 (Executes extended disk self-test)\n"
92 " smartctl -A -l selftest -q errorsonly /dev/rdsk/c0t0d0s0\n"
93 " (Prints Self-Test & Attribute errors)\n"
99 static const char *uscsidrvrs
[] = {
105 static const char *atadrvrs
[] = {
111 isdevtype(const char *dev_name
, const char *table
[], int tsize
)
113 char devpath
[MAXPATHLEN
];
117 if (realpath(dev_name
, devpath
) == NULL
)
120 if ((basename
= strrchr(devpath
, '/')) == NULL
)
125 for (i
= 0; i
< tsize
; i
++) {
126 int l
= strlen(table
[i
]);
127 if (strncmp(basename
, table
[i
], l
) == 0 && basename
[l
] == '@')
134 isscsidev(const char *path
)
136 return isdevtype(path
, uscsidrvrs
, sizeof (uscsidrvrs
) / sizeof (char *));
140 isatadev(const char *path
)
142 return isdevtype(path
, atadrvrs
, sizeof (atadrvrs
) / sizeof (char *));
145 // tries to guess device type given the name (a path)
146 int guess_device_type (const char* dev_name
) {
147 if (isscsidev(dev_name
))
148 return CONTROLLER_SCSI
;
149 else if (isatadev(dev_name
))
150 return CONTROLLER_ATA
;
152 return CONTROLLER_UNKNOWN
;
162 addpath(const char *path
, struct pathlist
*res
)
164 if (++res
->nnames
> res
->maxnames
) {
166 res
->names
= static_cast<char**>(realloc(res
->names
, res
->maxnames
* sizeof (char *)));
167 if (res
->names
== NULL
)
169 bytes
+= 16*sizeof(char *);
171 if (!(res
->names
[res
->nnames
-1] = CustomStrDup((char *)path
, 1, __LINE__
, filenameandversion
)))
177 grokdir(const char *dir
, struct pathlist
*res
, int testfun(const char *))
179 char pathbuf
[MAXPATHLEN
];
183 int isdisk
= strstr(dir
, "dsk") != NULL
;
186 len
= snprintf(pathbuf
, sizeof (pathbuf
), "%s/", dir
);
187 if (len
>= sizeof (pathbuf
))
194 while ((de
= readdir(dp
)) != NULL
) {
195 if (de
->d_name
[0] == '.')
198 if (strlen(de
->d_name
) + len
>= sizeof (pathbuf
))
202 /* Disk represented by slice 0 */
203 p
= strstr(de
->d_name
, "s0");
204 /* String doesn't end in "s0\0" */
205 if (p
== NULL
|| p
[2] != '\0')
208 /* Tape drive represented by the all-digit device */
209 for (p
= de
->d_name
; *p
; p
++)
210 if (!isdigit((int)(*p
)))
215 strcpy(&pathbuf
[len
], de
->d_name
);
216 if (testfun(pathbuf
)) {
217 if (addpath(pathbuf
, res
) == -1) {
228 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of
229 // smartd. Returns number of devices, or -1 if out of memory.
230 int make_device_names (char*** devlist
, const char* name
) {
233 res
.nnames
= res
.maxnames
= 0;
235 if (strcmp(name
, "SCSI") == 0) {
236 if (grokdir("/dev/rdsk", &res
, isscsidev
) == -1)
238 if (grokdir("/dev/rmt", &res
, isscsidev
) == -1)
240 } else if (strcmp(name
, "ATA") == 0) {
241 if (grokdir("/dev/rdsk", &res
, isatadev
) == -1)
244 // non-SCSI and non-ATA case not implemented
249 // shrink array to min possible size
250 res
.names
= static_cast<char**>(realloc(res
.names
, res
.nnames
* sizeof (char *)));
251 bytes
-= sizeof(char *)*(res
.maxnames
-res
.nnames
);
254 *devlist
= res
.names
;
258 // Like open(). Return integer handle, used by functions below only.
259 // type="ATA" or "SCSI".
260 int deviceopen(const char *pathname
, char *type
){
261 if (!strcmp(type
,"SCSI"))
262 return open(pathname
, O_RDWR
| O_NONBLOCK
);
263 else if (!strcmp(type
,"ATA"))
264 return open(pathname
, O_RDONLY
| O_NONBLOCK
);
269 // Like close(). Acts on handles returned by above function.
270 int deviceclose(int fd
){
275 // swap each 2-byte pairs in a sector
276 static void swap_sector(void *p
)
279 char t
, *cp
= static_cast<char*>(p
);
280 for(i
= 0; i
< 256; i
++) {
281 t
= cp
[0]; cp
[0] = cp
[1]; cp
[1] = t
;
287 // Interface to ATA devices. See os_linux.c
288 int ata_command_interface(int fd
, smart_command_set command
, int select
, char *data
){
293 case CHECK_POWER_MODE
:
294 /* currently not recognized */
297 return smart_read_data(fd
, data
);
298 case READ_THRESHOLDS
:
299 return smart_read_thresholds(fd
, data
);
301 return smart_read_log(fd
, select
, 1, data
);
303 err
= ata_identify(fd
, data
);
305 swap_sector(static_cast<void*>(data
));
308 err
= ata_pidentify(fd
, data
);
310 swap_sector(static_cast<void*>(data
));
313 return smart_enable(fd
);
315 return smart_disable(fd
);
317 return smart_status(fd
);
319 return smart_auto_offline(fd
, select
);
321 return smart_auto_save(fd
, select
);
322 case IMMEDIATE_OFFLINE
:
323 return smart_immediate_offline(fd
, select
);
325 return smart_status_check(fd
);
327 pout("Unrecognized command %d in ata_command_interface() of os_solaris.c\n", command
);
332 ARGUSED(fd
); ARGUSED(command
); ARGUSED(select
); ARGUSED(data
);
334 /* Above smart_* routines uses undocumented ioctls of "dada"
335 * driver, which is specific to SPARC Solaris. See
336 * os_solaris_ata.s for further details. x86 Solaris seems not to
337 * provide similar or alternative interface... */
345 #include <sys/scsi/generic/commands.h>
346 #include <sys/scsi/generic/status.h>
347 #include <sys/scsi/impl/types.h>
348 #include <sys/scsi/impl/uscsi.h>
350 // Interface to SCSI devices. See os_linux.c
351 int do_scsi_cmnd_io(int fd
, struct scsi_cmnd_io
* iop
, int report
)
353 struct uscsi_cmd uscsi
;
357 const unsigned char * ucp
= iop
->cmnd
;
360 np
= scsi_get_opcode_name(ucp
[0]);
361 pout(" [%s: ", np
? np
: "<unknown opcode>");
362 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
363 pout("%02x ", ucp
[k
]);
366 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
367 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
369 pout(" Outgoing data, len=%d%s:\n", (int)iop
->dxfer_len
,
370 (trunc
? " [only first 256 bytes shown]" : ""));
371 dStrHex((char *)iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
374 memset(&uscsi
, 0, sizeof (uscsi
));
376 uscsi
.uscsi_cdb
= reinterpret_cast<char*>(iop
->cmnd
);
377 uscsi
.uscsi_cdblen
= iop
->cmnd_len
;
378 if (iop
->timeout
== 0)
379 uscsi
.uscsi_timeout
= 60; /* 60 seconds */
381 uscsi
.uscsi_timeout
= iop
->timeout
;
382 uscsi
.uscsi_bufaddr
= reinterpret_cast<char*>(iop
->dxferp
);
383 uscsi
.uscsi_buflen
= iop
->dxfer_len
;
384 uscsi
.uscsi_rqbuf
= reinterpret_cast<char*>(iop
->sensep
);
385 uscsi
.uscsi_rqlen
= iop
->max_sense_len
;
387 switch (iop
->dxfer_dir
) {
389 case DXFER_FROM_DEVICE
:
390 uscsi
.uscsi_flags
= USCSI_READ
;
392 case DXFER_TO_DEVICE
:
393 uscsi
.uscsi_flags
= USCSI_WRITE
;
398 uscsi
.uscsi_flags
|= (USCSI_ISOLATE
| USCSI_RQENABLE
);
400 if (ioctl(fd
, USCSICMD
, &uscsi
)) {
403 if (! ((EIO
== err
) && uscsi
.uscsi_status
))
405 /* errno is set to EIO when a non-zero SCSI completion status given */
408 iop
->scsi_status
= uscsi
.uscsi_status
;
409 iop
->resid
= uscsi
.uscsi_resid
;
410 iop
->resp_sense_len
= iop
->max_sense_len
- uscsi
.uscsi_rqresid
;
414 int len
= iop
->resp_sense_len
;
416 if ((SCSI_STATUS_CHECK_CONDITION
== iop
->scsi_status
) &&
417 iop
->sensep
&& (len
> 3)) {
418 if ((iop
->sensep
[0] & 0x7f) > 0x71)
419 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
420 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
421 iop
->sensep
[2], iop
->sensep
[3]);
423 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
424 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
425 iop
->sensep
[12], iop
->sensep
[13]);
427 pout(" >>> Sense buffer, len=%d:\n", len
);
428 dStrHex((const char *)iop
->sensep
, ((len
> 252) ? 252 : len
) , 1);
430 } else if (iop
->scsi_status
)
431 pout(" status=%x\n", iop
->scsi_status
);
433 pout(" dxfer_len=%d, resid=%d\n", iop
->dxfer_len
, iop
->resid
);
435 len
= iop
->dxfer_len
- iop
->resid
;
437 trunc
= (len
> 256) ? 1 : 0;
438 pout(" Incoming data, len=%d%s:\n", len
,
439 (trunc
? " [only first 256 bytes shown]" : ""));
440 dStrHex((char *)iop
->dxferp
, (trunc
? 256 : len
) , 1);