4 * Home page of code is: http://smartmontools.sourceforge.net
6 * Copyright (C) 2003-6 SAWADA Keiji <smartmontools-support@lists.sourceforge.net>
7 * Copyright (C) 2003-6 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.c,v 1.26 2006/04/12 14:54:28 ballen4705 Exp $";
44 const char *os_XXXX_c_cvsid
="$Id: os_solaris.c,v 1.26 2006/04/12 14:54:28 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
= 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
= 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
){
274 static void swap_sector(void *p
)
277 unsigned char t
, *cp
= p
;
278 for(i
= 0; i
< 256; i
++) {
279 t
= cp
[0]; cp
[0] = cp
[1]; cp
[1] = t
;
284 // Interface to ATA devices. See os_linux.c
285 int marvell_command_interface(int fd
, smart_command_set command
, int select
, char *data
){
286 ARGUSED(fd
); ARGUSED(command
); ARGUSED(select
); ARGUSED(data
);
290 int ata_command_interface(int fd
, smart_command_set command
, int select
, char *data
){
295 case CHECK_POWER_MODE
:
296 /* currently not recognized */
299 return smart_read_data(fd
, data
);
300 case READ_THRESHOLDS
:
301 return smart_read_thresholds(fd
, data
);
303 return smart_read_log(fd
, select
, 1, data
);
305 err
= ata_identify(fd
, data
);
310 err
= ata_pidentify(fd
, data
);
315 return smart_enable(fd
);
317 return smart_disable(fd
);
319 return smart_status(fd
);
321 return smart_auto_offline(fd
, select
);
323 return smart_auto_save(fd
, select
);
324 case IMMEDIATE_OFFLINE
:
325 return smart_immediate_offline(fd
, select
);
327 return smart_status_check(fd
);
329 pout("Unrecognized command %d in ata_command_interface() of os_solaris.c\n", command
);
334 // avoid gcc warnings//
338 /* Above smart_* routines uses undocumented ioctls of "dada"
339 * driver, which is specific to SPARC Solaris. See
340 * os_solaris_ata.s for further details. x86 Solaris seems not to
341 * provide similar or alternative interface... */
348 // Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c
349 int escalade_command_interface(int fd
, int disknum
, int escalade_type
, smart_command_set command
, int select
, char *data
){
350 // avoid gcc warnings//
351 fd
=disknum
=escalade_type
=command
=select
=0;
360 #include <sys/scsi/generic/commands.h>
361 #include <sys/scsi/generic/status.h>
362 #include <sys/scsi/impl/types.h>
363 #include <sys/scsi/impl/uscsi.h>
365 // Interface to SCSI devices. See os_linux.c
366 int do_scsi_cmnd_io(int fd
, struct scsi_cmnd_io
* iop
, int report
) {
367 struct uscsi_cmd uscsi
;
371 const unsigned char * ucp
= iop
->cmnd
;
374 np
= scsi_get_opcode_name(ucp
[0]);
375 pout(" [%s: ", np
? np
: "<unknown opcode>");
376 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
377 pout("%02x ", ucp
[k
]);
379 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
380 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
382 pout("]\n Outgoing data, len=%d%s:\n", (int)iop
->dxfer_len
,
383 (trunc
? " [only first 256 bytes shown]" : ""));
384 dStrHex((char *)iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
391 memset(&uscsi
, 0, sizeof (uscsi
));
393 uscsi
.uscsi_cdb
= (void *)iop
->cmnd
;
394 uscsi
.uscsi_cdblen
= iop
->cmnd_len
;
395 if (iop
->timeout
== 0)
396 uscsi
.uscsi_timeout
= 60; /* XXX */
398 uscsi
.uscsi_timeout
= iop
->timeout
;
399 uscsi
.uscsi_bufaddr
= (void *)iop
->dxferp
;
400 uscsi
.uscsi_buflen
= iop
->dxfer_len
;
401 uscsi
.uscsi_rqbuf
= (void *)iop
->sensep
;
402 uscsi
.uscsi_rqlen
= iop
->max_sense_len
;
404 switch (iop
->dxfer_dir
) {
406 case DXFER_FROM_DEVICE
:
407 uscsi
.uscsi_flags
= USCSI_READ
;
409 case DXFER_TO_DEVICE
:
410 uscsi
.uscsi_flags
= USCSI_WRITE
;
415 uscsi
.uscsi_flags
|= USCSI_ISOLATE
;
417 if (ioctl(fd
, USCSICMD
, &uscsi
))
420 iop
->scsi_status
= uscsi
.uscsi_status
;
421 iop
->resid
= uscsi
.uscsi_resid
;
422 iop
->resp_sense_len
= iop
->max_sense_len
- uscsi
.uscsi_rqresid
;
425 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
428 pout(" Incoming data, len=%d%s:\n", (int)iop
->dxfer_len
,
429 (trunc
? " [only first 256 bytes shown]" : ""));
430 dStrHex((char *)iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);