4 * Home page of code is: http://www.smartmontools.org
6 * Copyright (C) 2003-08 SAWADA Keiji
7 * Copyright (C) 2003-15 Casper Dik
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 const char *os_XXXX_c_cvsid
="$Id: os_solaris.cpp 4253 2016-03-26 19:47:47Z chrfranke $" \
41 ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_SOLARIS_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID
;
43 // The printwarning() function warns about unimplemented functions
45 char *unimplemented
[2]={
46 "ATA command routine ata_command_interface()",
47 "3ware Escalade Controller command routine escalade_command_interface()",
50 int printwarning(int which
){
51 if (!unimplemented
[which
])
54 if (printedout
[which
])
60 "#######################################################################\n"
61 "%s NOT IMPLEMENTED under Solaris.\n"
62 "Please contact " PACKAGE_BUGREPORT
" if\n"
63 "you want to help in porting smartmontools to Solaris.\n"
64 "#######################################################################\n"
66 unimplemented
[which
]);
71 // print examples for smartctl
72 void print_smartctl_examples(){
73 printf("=================================================== SMARTCTL EXAMPLES =====\n\n");
74 #ifdef HAVE_GETOPT_LONG
76 " smartctl -a /dev/rdsk/c0t0d0s0 (Prints all SMART information)\n\n"
77 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/rdsk/c0t0d0s0\n"
78 " (Enables SMART on first disk)\n\n"
79 " smartctl -t long /dev/rdsk/c0t0d0s0 (Executes extended disk self-test)\n\n"
80 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/rdsk/c0t0d0s0\n"
81 " (Prints Self-Test & Attribute errors)\n"
85 " smartctl -a /dev/rdsk/c0t0d0s0 (Prints all SMART information)\n"
86 " smartctl -s on -o on -S on /dev/rdsk/c0t0d0s0 (Enables SMART on first disk)\n"
87 " smartctl -t long /dev/rdsk/c0t0d0s0 (Executes extended disk self-test)\n"
88 " smartctl -A -l selftest -q errorsonly /dev/rdsk/c0t0d0s0\n"
89 " (Prints Self-Test & Attribute errors)\n"
95 static const char *uscsidrvrs
[] = {
98 "disk", // SATA devices
102 static const char *atadrvrs
[] = {
108 isdevtype(const char *dev_name
, const char *table
[], int tsize
)
110 char devpath
[MAXPATHLEN
];
114 if (realpath(dev_name
, devpath
) == NULL
)
117 if ((basename
= strrchr(devpath
, '/')) == NULL
)
122 for (i
= 0; i
< tsize
; i
++) {
123 int l
= strlen(table
[i
]);
124 if (strncmp(basename
, table
[i
], l
) == 0 && basename
[l
] == '@')
131 isscsidev(const char *path
)
133 return isdevtype(path
, uscsidrvrs
, sizeof (uscsidrvrs
) / sizeof (char *));
137 isatadev(const char *path
)
139 return isdevtype(path
, atadrvrs
, sizeof (atadrvrs
) / sizeof (char *));
142 // tries to guess device type given the name (a path)
143 int guess_device_type (const char* dev_name
) {
144 if (isscsidev(dev_name
))
145 return CONTROLLER_SCSI
;
146 else if (isatadev(dev_name
))
147 return CONTROLLER_ATA
;
149 return CONTROLLER_UNKNOWN
;
159 addpath(const char *path
, struct pathlist
*res
)
161 if (++res
->nnames
> res
->maxnames
) {
163 res
->names
= static_cast<char**>(realloc(res
->names
, res
->maxnames
* sizeof (char *)));
164 if (res
->names
== NULL
)
167 if (!(res
->names
[res
->nnames
-1] = strdup(path
)))
173 grokdir(const char *dir
, struct pathlist
*res
, int testfun(const char *))
175 char pathbuf
[MAXPATHLEN
];
179 int isdisk
= strstr(dir
, "dsk") != NULL
;
182 len
= snprintf(pathbuf
, sizeof (pathbuf
), "%s/", dir
);
183 if (len
>= sizeof (pathbuf
))
190 while ((de
= readdir(dp
)) != NULL
) {
191 if (de
->d_name
[0] == '.')
194 if (strlen(de
->d_name
) + len
>= sizeof (pathbuf
))
198 /* Disk represented by slice 0 */
199 p
= strstr(de
->d_name
, "s0");
200 /* String doesn't end in "s0\0" */
201 if (p
== NULL
|| p
[2] != '\0')
204 /* Tape drive represented by the all-digit device */
205 for (p
= de
->d_name
; *p
; p
++)
206 if (!isdigit((int)(*p
)))
211 strcpy(&pathbuf
[len
], de
->d_name
);
212 if (testfun(pathbuf
)) {
213 if (addpath(pathbuf
, res
) == -1) {
224 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of
225 // smartd. Returns number of devices, or -1 if out of memory.
226 int make_device_names (char*** devlist
, const char* name
) {
229 res
.nnames
= res
.maxnames
= 0;
231 if (strcmp(name
, "SCSI") == 0) {
232 if (grokdir("/dev/rdsk", &res
, isscsidev
) == -1)
234 if (grokdir("/dev/rmt", &res
, isscsidev
) == -1)
236 } else if (strcmp(name
, "ATA") == 0) {
237 if (grokdir("/dev/rdsk", &res
, isatadev
) == -1)
240 // non-SCSI and non-ATA case not implemented
245 // shrink array to min possible size
246 res
.names
= static_cast<char**>(realloc(res
.names
, res
.nnames
* sizeof (char *)));
249 *devlist
= res
.names
;
253 // Like open(). Return integer handle, used by functions below only.
254 // type="ATA" or "SCSI".
255 int deviceopen(const char *pathname
, char *type
){
256 if (!strcmp(type
,"SCSI"))
257 return open(pathname
, O_RDWR
| O_NONBLOCK
);
258 else if (!strcmp(type
,"ATA"))
259 return open(pathname
, O_RDONLY
| O_NONBLOCK
);
264 // Like close(). Acts on handles returned by above function.
265 int deviceclose(int fd
){
269 #if defined(WITH_SOLARIS_SPARC_ATA)
270 // swap each 2-byte pairs in a sector
271 static void swap_sector(void *p
)
274 char t
, *cp
= static_cast<char*>(p
);
275 for(i
= 0; i
< 256; i
++) {
276 t
= cp
[0]; cp
[0] = cp
[1]; cp
[1] = t
;
282 // Interface to ATA devices. See os_linux.c
283 int ata_command_interface(int fd
, smart_command_set command
, int select
, char *data
){
284 #if defined(WITH_SOLARIS_SPARC_ATA)
288 case CHECK_POWER_MODE
:
289 /* currently not recognized */
292 return smart_read_data(fd
, data
);
293 case READ_THRESHOLDS
:
294 return smart_read_thresholds(fd
, data
);
296 return smart_read_log(fd
, select
, 1, data
);
298 err
= ata_identify(fd
, data
);
300 swap_sector(static_cast<void*>(data
));
303 err
= ata_pidentify(fd
, data
);
305 swap_sector(static_cast<void*>(data
));
308 return smart_enable(fd
);
310 return smart_disable(fd
);
312 return smart_status(fd
);
314 return smart_auto_offline(fd
, select
);
316 return smart_auto_save(fd
, select
);
317 case IMMEDIATE_OFFLINE
:
318 return smart_immediate_offline(fd
, select
);
320 return smart_status_check(fd
);
322 pout("Unrecognized command %d in ata_command_interface() of os_solaris.c\n", command
);
326 #else /* WITH_SOLARIS_SPARC_ATA */
327 ARGUSED(fd
); ARGUSED(command
); ARGUSED(select
); ARGUSED(data
);
329 /* Above smart_* routines uses undocumented ioctls of "dada"
330 * driver, which is specific to SPARC Solaris. See
331 * os_solaris_ata.s for further details. x86 Solaris seems not to
332 * provide similar or alternative interface... */
340 #include <sys/scsi/generic/commands.h>
341 #include <sys/scsi/generic/status.h>
342 #include <sys/scsi/impl/types.h>
343 #include <sys/scsi/impl/uscsi.h>
345 // Interface to SCSI devices. See os_linux.c
346 int do_scsi_cmnd_io(int fd
, struct scsi_cmnd_io
* iop
, int report
)
348 struct uscsi_cmd uscsi
;
352 const unsigned char * ucp
= iop
->cmnd
;
355 np
= scsi_get_opcode_name(ucp
[0]);
356 pout(" [%s: ", np
? np
: "<unknown opcode>");
357 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
358 pout("%02x ", ucp
[k
]);
361 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
362 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
364 pout(" Outgoing data, len=%d%s:\n", (int)iop
->dxfer_len
,
365 (trunc
? " [only first 256 bytes shown]" : ""));
366 dStrHex((char *)iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
369 memset(&uscsi
, 0, sizeof (uscsi
));
371 uscsi
.uscsi_cdb
= reinterpret_cast<char*>(iop
->cmnd
);
372 uscsi
.uscsi_cdblen
= iop
->cmnd_len
;
373 if (iop
->timeout
== 0)
374 uscsi
.uscsi_timeout
= 60; /* 60 seconds */
376 uscsi
.uscsi_timeout
= iop
->timeout
;
377 uscsi
.uscsi_bufaddr
= reinterpret_cast<char*>(iop
->dxferp
);
378 uscsi
.uscsi_buflen
= iop
->dxfer_len
;
379 uscsi
.uscsi_rqbuf
= reinterpret_cast<char*>(iop
->sensep
);
380 uscsi
.uscsi_rqlen
= iop
->max_sense_len
;
382 switch (iop
->dxfer_dir
) {
384 case DXFER_FROM_DEVICE
:
385 uscsi
.uscsi_flags
= USCSI_READ
;
387 case DXFER_TO_DEVICE
:
388 uscsi
.uscsi_flags
= USCSI_WRITE
;
393 uscsi
.uscsi_flags
|= (USCSI_ISOLATE
| USCSI_RQENABLE
| USCSI_SILENT
);
395 if (ioctl(fd
, USCSICMD
, &uscsi
)) {
398 if (! ((EIO
== err
) && uscsi
.uscsi_status
))
400 /* errno is set to EIO when a non-zero SCSI completion status given */
403 iop
->scsi_status
= uscsi
.uscsi_status
;
404 iop
->resid
= uscsi
.uscsi_resid
;
405 iop
->resp_sense_len
= iop
->max_sense_len
- uscsi
.uscsi_rqresid
;
409 int len
= iop
->resp_sense_len
;
411 if ((SCSI_STATUS_CHECK_CONDITION
== iop
->scsi_status
) &&
412 iop
->sensep
&& (len
> 3)) {
413 if ((iop
->sensep
[0] & 0x7f) > 0x71)
414 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
415 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
416 iop
->sensep
[2], iop
->sensep
[3]);
418 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
419 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
420 iop
->sensep
[12], iop
->sensep
[13]);
422 pout(" >>> Sense buffer, len=%d:\n", len
);
423 dStrHex((const char *)iop
->sensep
, ((len
> 252) ? 252 : len
) , 1);
425 } else if (iop
->scsi_status
)
426 pout(" status=%x\n", iop
->scsi_status
);
428 pout(" dxfer_len=%d, resid=%d\n", iop
->dxfer_len
, iop
->resid
);
430 len
= iop
->dxfer_len
- iop
->resid
;
432 trunc
= (len
> 256) ? 1 : 0;
433 pout(" Incoming data, len=%d%s:\n", len
,
434 (trunc
? " [only first 256 bytes shown]" : ""));
435 dStrHex((char *)iop
->dxferp
, (trunc
? 256 : len
) , 1);