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 * SPDX-License-Identifier: GPL-2.0-or-later
18 #include <sys/param.h>
20 // These are needed to define prototypes for the functions defined below
27 // This is to include whatever prototypes you define in os_solaris.h
28 #include "os_solaris.h"
30 #define ARGUSED(x) ((void)(x))
32 const char *os_XXXX_c_cvsid
="$Id: os_solaris.cpp 4805 2018-10-09 19:34:46Z chrfranke $" \
33 ATACMDS_H_CVSID CONFIG_H_CVSID OS_SOLARIS_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID
;
35 // The printwarning() function warns about unimplemented functions
37 char *unimplemented
[2]={
38 "ATA command routine ata_command_interface()",
39 "3ware Escalade Controller command routine escalade_command_interface()",
42 int printwarning(int which
){
43 if (!unimplemented
[which
])
46 if (printedout
[which
])
52 "#######################################################################\n"
53 "%s NOT IMPLEMENTED under Solaris.\n"
54 "Please contact " PACKAGE_BUGREPORT
" if\n"
55 "you want to help in porting smartmontools to Solaris.\n"
56 "#######################################################################\n"
58 unimplemented
[which
]);
63 // print examples for smartctl
64 void print_smartctl_examples(){
65 printf("=================================================== SMARTCTL EXAMPLES =====\n\n"
66 " smartctl -a /dev/rdsk/c0t0d0s0 (Prints all SMART information)\n\n"
67 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/rdsk/c0t0d0s0\n"
68 " (Enables SMART on first disk)\n\n"
69 " smartctl -t long /dev/rdsk/c0t0d0s0 (Executes extended disk self-test)\n\n"
70 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/rdsk/c0t0d0s0\n"
71 " (Prints Self-Test & Attribute errors)\n"
76 static const char *uscsidrvrs
[] = {
79 "disk", // SATA devices
83 static const char *atadrvrs
[] = {
89 isdevtype(const char *dev_name
, const char *table
[], int tsize
)
91 char devpath
[MAXPATHLEN
];
95 if (realpath(dev_name
, devpath
) == NULL
)
98 if ((basename
= strrchr(devpath
, '/')) == NULL
)
103 for (i
= 0; i
< tsize
; i
++) {
104 int l
= strlen(table
[i
]);
105 if (strncmp(basename
, table
[i
], l
) == 0 && basename
[l
] == '@')
112 isscsidev(const char *path
)
114 return isdevtype(path
, uscsidrvrs
, sizeof (uscsidrvrs
) / sizeof (char *));
118 isatadev(const char *path
)
120 return isdevtype(path
, atadrvrs
, sizeof (atadrvrs
) / sizeof (char *));
123 // tries to guess device type given the name (a path)
124 int guess_device_type (const char* dev_name
) {
125 if (isscsidev(dev_name
))
126 return CONTROLLER_SCSI
;
127 else if (isatadev(dev_name
))
128 return CONTROLLER_ATA
;
130 return CONTROLLER_UNKNOWN
;
140 addpath(const char *path
, struct pathlist
*res
)
142 if (++res
->nnames
> res
->maxnames
) {
144 res
->names
= static_cast<char**>(realloc(res
->names
, res
->maxnames
* sizeof (char *)));
145 if (res
->names
== NULL
)
148 if (!(res
->names
[res
->nnames
-1] = strdup(path
)))
154 grokdir(const char *dir
, struct pathlist
*res
, int testfun(const char *))
156 char pathbuf
[MAXPATHLEN
];
160 int isdisk
= strstr(dir
, "dsk") != NULL
;
163 len
= snprintf(pathbuf
, sizeof (pathbuf
), "%s/", dir
);
164 if (len
>= sizeof (pathbuf
))
171 while ((de
= readdir(dp
)) != NULL
) {
172 if (de
->d_name
[0] == '.')
175 if (strlen(de
->d_name
) + len
>= sizeof (pathbuf
))
179 /* Disk represented by slice 0 */
180 p
= strstr(de
->d_name
, "s0");
181 /* String doesn't end in "s0\0" */
182 if (p
== NULL
|| p
[2] != '\0')
185 /* Tape drive represented by the all-digit device */
186 for (p
= de
->d_name
; *p
; p
++)
187 if (!isdigit((int)(*p
)))
192 strcpy(&pathbuf
[len
], de
->d_name
);
193 if (testfun(pathbuf
)) {
194 if (addpath(pathbuf
, res
) == -1) {
205 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of
206 // smartd. Returns number of devices, or -1 if out of memory.
207 int make_device_names (char*** devlist
, const char* name
) {
210 res
.nnames
= res
.maxnames
= 0;
212 if (strcmp(name
, "SCSI") == 0) {
213 if (grokdir("/dev/rdsk", &res
, isscsidev
) == -1)
215 if (grokdir("/dev/rmt", &res
, isscsidev
) == -1)
217 } else if (strcmp(name
, "ATA") == 0) {
218 if (grokdir("/dev/rdsk", &res
, isatadev
) == -1)
221 // non-SCSI and non-ATA case not implemented
226 // shrink array to min possible size
227 res
.names
= static_cast<char**>(realloc(res
.names
, res
.nnames
* sizeof (char *)));
230 *devlist
= res
.names
;
234 // Like open(). Return integer handle, used by functions below only.
235 // type="ATA" or "SCSI".
236 int deviceopen(const char *pathname
, char *type
){
237 if (!strcmp(type
,"SCSI"))
238 return open(pathname
, O_RDWR
| O_NONBLOCK
);
239 else if (!strcmp(type
,"ATA"))
240 return open(pathname
, O_RDONLY
| O_NONBLOCK
);
245 // Like close(). Acts on handles returned by above function.
246 int deviceclose(int fd
){
250 #if defined(WITH_SOLARIS_SPARC_ATA)
251 // swap each 2-byte pairs in a sector
252 static void swap_sector(void *p
)
255 char t
, *cp
= static_cast<char*>(p
);
256 for(i
= 0; i
< 256; i
++) {
257 t
= cp
[0]; cp
[0] = cp
[1]; cp
[1] = t
;
263 // Interface to ATA devices. See os_linux.c
264 int ata_command_interface(int fd
, smart_command_set command
, int select
, char *data
){
265 #if defined(WITH_SOLARIS_SPARC_ATA)
269 case CHECK_POWER_MODE
:
270 /* currently not recognized */
273 return smart_read_data(fd
, data
);
274 case READ_THRESHOLDS
:
275 return smart_read_thresholds(fd
, data
);
277 return smart_read_log(fd
, select
, 1, data
);
279 err
= ata_identify(fd
, data
);
281 swap_sector(static_cast<void*>(data
));
284 err
= ata_pidentify(fd
, data
);
286 swap_sector(static_cast<void*>(data
));
289 return smart_enable(fd
);
291 return smart_disable(fd
);
293 return smart_status(fd
);
295 return smart_auto_offline(fd
, select
);
297 return smart_auto_save(fd
, select
);
298 case IMMEDIATE_OFFLINE
:
299 return smart_immediate_offline(fd
, select
);
301 return smart_status_check(fd
);
303 pout("Unrecognized command %d in ata_command_interface() of os_solaris.c\n", command
);
307 #else /* WITH_SOLARIS_SPARC_ATA */
308 ARGUSED(fd
); ARGUSED(command
); ARGUSED(select
); ARGUSED(data
);
310 /* Above smart_* routines uses undocumented ioctls of "dada"
311 * driver, which is specific to SPARC Solaris. See
312 * os_solaris_ata.s for further details. x86 Solaris seems not to
313 * provide similar or alternative interface... */
321 #include <sys/scsi/generic/commands.h>
322 #include <sys/scsi/generic/status.h>
323 #include <sys/scsi/impl/types.h>
324 #include <sys/scsi/impl/uscsi.h>
326 // Interface to SCSI devices. See os_linux.c
327 int do_scsi_cmnd_io(int fd
, struct scsi_cmnd_io
* iop
, int report
)
329 struct uscsi_cmd uscsi
;
333 const unsigned char * ucp
= iop
->cmnd
;
336 np
= scsi_get_opcode_name(ucp
[0]);
337 pout(" [%s: ", np
? np
: "<unknown opcode>");
338 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
339 pout("%02x ", ucp
[k
]);
342 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
343 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
345 pout(" Outgoing data, len=%d%s:\n", (int)iop
->dxfer_len
,
346 (trunc
? " [only first 256 bytes shown]" : ""));
347 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
350 memset(&uscsi
, 0, sizeof (uscsi
));
352 uscsi
.uscsi_cdb
= reinterpret_cast<char*>(iop
->cmnd
);
353 uscsi
.uscsi_cdblen
= iop
->cmnd_len
;
354 if (iop
->timeout
== 0)
355 uscsi
.uscsi_timeout
= 60; /* 60 seconds */
357 uscsi
.uscsi_timeout
= iop
->timeout
;
358 uscsi
.uscsi_bufaddr
= reinterpret_cast<char*>(iop
->dxferp
);
359 uscsi
.uscsi_buflen
= iop
->dxfer_len
;
360 uscsi
.uscsi_rqbuf
= reinterpret_cast<char*>(iop
->sensep
);
361 uscsi
.uscsi_rqlen
= iop
->max_sense_len
;
363 switch (iop
->dxfer_dir
) {
365 case DXFER_FROM_DEVICE
:
366 uscsi
.uscsi_flags
= USCSI_READ
;
368 case DXFER_TO_DEVICE
:
369 uscsi
.uscsi_flags
= USCSI_WRITE
;
374 uscsi
.uscsi_flags
|= (USCSI_ISOLATE
| USCSI_RQENABLE
| USCSI_SILENT
);
376 if (ioctl(fd
, USCSICMD
, &uscsi
)) {
379 if (! ((EIO
== err
) && uscsi
.uscsi_status
))
381 /* errno is set to EIO when a non-zero SCSI completion status given */
384 iop
->scsi_status
= uscsi
.uscsi_status
;
385 iop
->resid
= uscsi
.uscsi_resid
;
386 iop
->resp_sense_len
= iop
->max_sense_len
- uscsi
.uscsi_rqresid
;
390 int len
= iop
->resp_sense_len
;
392 if ((SCSI_STATUS_CHECK_CONDITION
== iop
->scsi_status
) &&
393 iop
->sensep
&& (len
> 3)) {
394 if ((iop
->sensep
[0] & 0x7f) > 0x71)
395 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
396 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
397 iop
->sensep
[2], iop
->sensep
[3]);
399 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
400 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
401 iop
->sensep
[12], iop
->sensep
[13]);
403 pout(" >>> Sense buffer, len=%d:\n", len
);
404 dStrHex(iop
->sensep
, ((len
> 252) ? 252 : len
) , 1);
406 } else if (iop
->scsi_status
)
407 pout(" status=%x\n", iop
->scsi_status
);
409 pout(" dxfer_len=%d, resid=%d\n", iop
->dxfer_len
, iop
->resid
);
411 len
= iop
->dxfer_len
- iop
->resid
;
413 trunc
= (len
> 256) ? 1 : 0;
414 pout(" Incoming data, len=%d%s:\n", len
,
415 (trunc
? " [only first 256 bytes shown]" : ""));
416 dStrHex(iop
->dxferp
, (trunc
? 256 : len
) , 1);