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
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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,v 1.32 2008/06/12 21:46:31 ballen4705 Exp $";
44 const char *os_XXXX_c_cvsid
="$Id: os_solaris.cpp,v 1.32 2008/06/12 21:46:31 ballen4705 Exp $" \
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 marvell_command_interface(int fd
, smart_command_set command
, int select
, char *data
){
289 ARGUSED(fd
); ARGUSED(command
); ARGUSED(select
); ARGUSED(data
);
293 int highpoint_command_interface(int fd
, smart_command_set command
, int select
, char *data
)
295 ARGUSED(fd
); ARGUSED(command
); ARGUSED(select
); ARGUSED(data
);
299 int ata_command_interface(int fd
, smart_command_set command
, int select
, char *data
){
304 case CHECK_POWER_MODE
:
305 /* currently not recognized */
308 return smart_read_data(fd
, data
);
309 case READ_THRESHOLDS
:
310 return smart_read_thresholds(fd
, data
);
312 return smart_read_log(fd
, select
, 1, data
);
314 err
= ata_identify(fd
, data
);
316 swap_sector(static_cast<void*>(data
));
319 err
= ata_pidentify(fd
, data
);
321 swap_sector(static_cast<void*>(data
));
324 return smart_enable(fd
);
326 return smart_disable(fd
);
328 return smart_status(fd
);
330 return smart_auto_offline(fd
, select
);
332 return smart_auto_save(fd
, select
);
333 case IMMEDIATE_OFFLINE
:
334 return smart_immediate_offline(fd
, select
);
336 return smart_status_check(fd
);
338 pout("Unrecognized command %d in ata_command_interface() of os_solaris.c\n", command
);
343 ARGUSED(fd
); ARGUSED(command
); ARGUSED(select
); ARGUSED(data
);
345 /* Above smart_* routines uses undocumented ioctls of "dada"
346 * driver, which is specific to SPARC Solaris. See
347 * os_solaris_ata.s for further details. x86 Solaris seems not to
348 * provide similar or alternative interface... */
355 // Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c
356 int escalade_command_interface(int fd
, int disknum
, int escalade_type
, smart_command_set command
, int select
, char *data
){
357 ARGUSED(fd
); ARGUSED(disknum
); ARGUSED(escalade_type
);
358 ARGUSED(command
); ARGUSED(select
); ARGUSED(data
);
365 int areca_command_interface(int fd
, int disknum
, smart_command_set command
, int select
, char *data
){
366 ARGUSED(fd
); ARGUSED(disknum
);
367 ARGUSED(command
); ARGUSED(select
); ARGUSED(data
);
375 #include <sys/scsi/generic/commands.h>
376 #include <sys/scsi/generic/status.h>
377 #include <sys/scsi/impl/types.h>
378 #include <sys/scsi/impl/uscsi.h>
380 // Interface to SCSI devices. See os_linux.c
381 int do_scsi_cmnd_io(int fd
, struct scsi_cmnd_io
* iop
, int report
)
383 struct uscsi_cmd uscsi
;
387 const unsigned char * ucp
= iop
->cmnd
;
390 np
= scsi_get_opcode_name(ucp
[0]);
391 pout(" [%s: ", np
? np
: "<unknown opcode>");
392 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
393 pout("%02x ", ucp
[k
]);
396 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
397 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
399 pout(" Outgoing data, len=%d%s:\n", (int)iop
->dxfer_len
,
400 (trunc
? " [only first 256 bytes shown]" : ""));
401 dStrHex((char *)iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
404 memset(&uscsi
, 0, sizeof (uscsi
));
406 uscsi
.uscsi_cdb
= reinterpret_cast<char*>(iop
->cmnd
);
407 uscsi
.uscsi_cdblen
= iop
->cmnd_len
;
408 if (iop
->timeout
== 0)
409 uscsi
.uscsi_timeout
= 60; /* 60 seconds */
411 uscsi
.uscsi_timeout
= iop
->timeout
;
412 uscsi
.uscsi_bufaddr
= reinterpret_cast<char*>(iop
->dxferp
);
413 uscsi
.uscsi_buflen
= iop
->dxfer_len
;
414 uscsi
.uscsi_rqbuf
= reinterpret_cast<char*>(iop
->sensep
);
415 uscsi
.uscsi_rqlen
= iop
->max_sense_len
;
417 switch (iop
->dxfer_dir
) {
419 case DXFER_FROM_DEVICE
:
420 uscsi
.uscsi_flags
= USCSI_READ
;
422 case DXFER_TO_DEVICE
:
423 uscsi
.uscsi_flags
= USCSI_WRITE
;
428 uscsi
.uscsi_flags
|= (USCSI_ISOLATE
| USCSI_RQENABLE
);
430 if (ioctl(fd
, USCSICMD
, &uscsi
)) {
433 if (! ((EIO
== err
) && uscsi
.uscsi_status
))
435 /* errno is set to EIO when a non-zero SCSI completion status given */
438 iop
->scsi_status
= uscsi
.uscsi_status
;
439 iop
->resid
= uscsi
.uscsi_resid
;
440 iop
->resp_sense_len
= iop
->max_sense_len
- uscsi
.uscsi_rqresid
;
444 int len
= iop
->resp_sense_len
;
446 if ((SCSI_STATUS_CHECK_CONDITION
== iop
->scsi_status
) &&
447 iop
->sensep
&& (len
> 3)) {
448 pout(" status=0x%x: sense_key=0x%x asc=0x%x ascq=0x%x\n",
449 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
450 iop
->sensep
[12], iop
->sensep
[13]);
452 pout(" >>> Sense buffer, len=%d:\n", len
);
453 dStrHex((const char *)iop
->sensep
, ((len
> 252) ? 252 : len
) , 1);
455 } else if (iop
->scsi_status
)
456 pout(" status=%x\n", iop
->scsi_status
);
458 pout(" dxfer_len=%d, resid=%d\n", iop
->dxfer_len
, iop
->resid
);
460 len
= iop
->dxfer_len
- iop
->resid
;
462 trunc
= (len
> 256) ? 1 : 0;
463 pout(" Incoming data, len=%d%s:\n", len
,
464 (trunc
? " [only first 256 bytes shown]" : ""));
465 dStrHex((char *)iop
->dxferp
, (trunc
? 256 : len
) , 1);