4 * Home page of code is: http://www.smartmontools.org
6 * Copyright (C) 2007 Joerg Hering
8 * SPDX-License-Identifier: GPL-2.0-or-later
11 // This is needed for the various HAVE_* macros and PROJECT_* macros.
14 // These are needed to define prototypes and structures for the
15 // functions defined below
20 // This is to include whatever structures and prototypes you define in
22 #include "os_qnxnto.h"
25 // Needed by '-V' option (CVS versioning) of smartd/smartctl. You
26 // should have one *_H_CVSID macro appearing below for each file
27 // appearing with #include "*.h" above. Please list these (below) in
28 // alphabetic/dictionary order.
29 const char *os_XXXX_c_cvsid
="$Id: os_qnxnto.cpp 4842 2018-12-02 16:07:26Z chrfranke $" \
30 ATACMDS_H_CVSID CONFIG_H_CVSID OS_QNXNTO_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID
;
33 // This is here to prevent compiler warnings for unused arguments of
35 #define ARGUSED(x) ((void)(x))
37 //----------------------------------------------------------------------------------------------
39 static int ata_sense_data(void *sdata
,int *error
,int *key
,int *asc
,int *ascq
);
40 static int ata_interpret_sense(struct cam_pass_thru
*cpt
,void *sense
,int *status
,int rcount
);
41 static int ata_pass_thru(int fd
,struct cam_pass_thru
*pcpt
);
43 // print examples for smartctl. You should modify this function so
44 // that the device paths are sensible for your OS, and to eliminate
45 // unsupported commands (eg, 3ware controllers).
46 void print_smartctl_examples(){
47 printf("=================================================== SMARTCTL EXAMPLES =====\n\n"
48 " smartctl -a /dev/hd0 (Prints all SMART information)\n\n"
49 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/hd0\n"
50 " (Enables SMART on first disk)\n\n"
51 " smartctl -t long /dev/hd0 (Executes extended disk self-test)\n\n"
52 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hd0\n"
53 " (Prints Self-Test & Attribute errors)\n"
54 " smartctl -a --device=3ware,2 /dev/sda\n"
55 " (Prints all SMART info for 3rd ATA disk on 3ware RAID controller)\n"
60 // tries to guess device type given the name (a path). See utility.h
62 static const char *net_dev_prefix
= "/dev/";
63 static const char *net_dev_ata_disk
= "hd";
65 int guess_device_type (const char* dev_name
)
67 int len
,dev_prefix_len
;
68 dev_prefix_len
=strlen(net_dev_prefix
);
69 if(!dev_name
||!(len
=strlen(dev_name
)))
70 return(CONTROLLER_UNKNOWN
);
71 if (!strncmp(net_dev_prefix
,dev_name
,dev_prefix_len
))
73 if(len
<=dev_prefix_len
)
74 return(CONTROLLER_UNKNOWN
);
76 dev_name
+= dev_prefix_len
;
78 if(!strncmp(net_dev_ata_disk
,dev_name
,strlen(net_dev_ata_disk
)))
79 return(CONTROLLER_ATA
);
80 return(CONTROLLER_UNKNOWN
);
83 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of
84 // smartd. Returns number N of devices, or -1 if out of
85 // memory. Allocates N+1 arrays: one of N pointers (devlist); the
86 // other N arrays each contain null-terminated character strings. In
87 // the case N==0, no arrays are allocated because the array of 0
88 // pointers has zero length, equivalent to calling malloc(0).
89 int make_device_names (char*** devlist
, const char* name
) {
95 // Like open(). Return non-negative integer handle, only used by the
96 // functions below. type=="ATA" or "SCSI". If you need to store
97 // extra information about your devices, create a private internal
98 // array within this file (see os_freebsd.cpp for an example). If you
99 // can not open the device (permission denied, does not exist, etc)
100 // set errno as open() does and return <0.
101 int deviceopen(const char *pathname
, char *type
)
103 if(!strcmp(type
, "ATA"))
104 return(open(pathname
,O_RDWR
|O_NONBLOCK
));
109 // Like close(). Acts only on integer handles returned by
110 // deviceopen() above.
111 int deviceclose(int fd
)
115 //----------------------------------------------------------------------------------------------
116 // Interface to ATA devices. See os_linux.cpp for the canonical example.
117 // DETAILED DESCRIPTION OF ARGUMENTS
118 // device: is the integer handle provided by deviceopen()
119 // command: defines the different operations, see atacmds.h
120 // select: additional input data IF NEEDED (which log, which type of
122 // data: location to write output data, IF NEEDED (1 or 512 bytes).
123 // Note: not all commands use all arguments.
124 // RETURN VALUES (for all commands BUT command==STATUS_CHECK)
125 // -1 if the command failed
126 // 0 if the command succeeded,
127 // RETURN VALUES if command==STATUS_CHECK
128 // -1 if the command failed OR the disk SMART status can't be determined
129 // 0 if the command succeeded and disk SMART status is "OK"
130 // 1 if the command succeeded and disk SMART status is "FAILING"
131 int ata_command_interface(int fd
,smart_command_set command
,int select
,char *data
)
133 struct cam_pass_thru cpt
;
137 memset(&cpt
,0x00,sizeof(struct cam_pass_thru
));
138 cdb
=(CDB
*)cpt
.cam_cdb
;
143 cpt
.cam_flags
= CAM_DIR_IN
;
144 cpt
.cam_cdb_len
= 16;
145 cpt
.cam_dxfer_len
= 512;
146 cpt
.cam_data_ptr
= (uint32_t)data
;
147 cpt
.cam_sense_len
= sizeof(sense
);
148 cpt
.cam_sense_ptr
= (uint32_t)&sense
;
149 cdb
->ata_pass_thru
.opcode
= SC_ATA_PT16
;
150 cdb
->ata_pass_thru
.protocol
= ATA_PROTO_PIO_DATA_IN
;
151 cdb
->ata_pass_thru
.flags
= ATA_FLG_T_DIR
|ATA_FLG_TLEN_STPSIU
;
152 cdb
->ata_pass_thru
.command
= ATA_SMART_CMD
;
153 cdb
->ata_pass_thru
.features
= ATA_SMART_READ_VALUES
;
154 cdb
->ata_pass_thru
.lba_mid
= ATA_SMART_LBA_MID_SIG
;
155 cdb
->ata_pass_thru
.lba_high
= ATA_SMART_LBA_HI_SIG
;
157 case READ_THRESHOLDS
:
158 cpt
.cam_flags
= CAM_DIR_IN
;
159 cpt
.cam_cdb_len
= 16;
160 cpt
.cam_dxfer_len
= 512;
161 cpt
.cam_data_ptr
= (uint32_t)data
;
162 cpt
.cam_sense_len
= sizeof(sense
);
163 cpt
.cam_sense_ptr
= (uint32_t)&sense
;
164 cdb
->ata_pass_thru
.opcode
= SC_ATA_PT16
;
165 cdb
->ata_pass_thru
.protocol
= ATA_PROTO_PIO_DATA_IN
;
166 cdb
->ata_pass_thru
.flags
= ATA_FLG_T_DIR
|ATA_FLG_TLEN_STPSIU
;
167 cdb
->ata_pass_thru
.command
= ATA_SMART_CMD
;
168 cdb
->ata_pass_thru
.features
= ATA_SMART_READ_THRESHOLDS
;
169 cdb
->ata_pass_thru
.lba_mid
= ATA_SMART_LBA_MID_SIG
;
170 cdb
->ata_pass_thru
.lba_high
= ATA_SMART_LBA_HI_SIG
;
173 cpt
.cam_flags
= CAM_DIR_IN
;
174 cpt
.cam_cdb_len
= 16;
175 cpt
.cam_dxfer_len
= 512;
176 cpt
.cam_data_ptr
= (uint32_t)data
;
177 cpt
.cam_sense_len
= sizeof(sense
);
178 cpt
.cam_sense_ptr
= (uint32_t)&sense
;
179 cdb
->ata_pass_thru
.opcode
= SC_ATA_PT16
;
180 cdb
->ata_pass_thru
.protocol
= ATA_PROTO_PIO_DATA_IN
;
181 cdb
->ata_pass_thru
.flags
= ATA_FLG_T_DIR
|ATA_FLG_TLEN_STPSIU
;
182 cdb
->ata_pass_thru
.command
= ATA_SMART_CMD
;
183 cdb
->ata_pass_thru
.features
= ATA_SMART_READ_LOG_SECTOR
;
184 cdb
->ata_pass_thru
.sector_count
= 1;
185 cdb
->ata_pass_thru
.lba_low
= select
;
186 cdb
->ata_pass_thru
.lba_mid
= ATA_SMART_LBA_MID_SIG
;
187 cdb
->ata_pass_thru
.lba_high
= ATA_SMART_LBA_HI_SIG
;
193 cpt
.cam_flags
= CAM_DIR_IN
;
194 cpt
.cam_cdb_len
= 16;
195 cpt
.cam_dxfer_len
= 512;
196 cpt
.cam_data_ptr
= (uint32_t)data
;
197 cpt
.cam_sense_len
= sizeof(sense
);
198 cpt
.cam_sense_ptr
= (uint32_t)&sense
;
199 cdb
->ata_pass_thru
.opcode
= SC_ATA_PT16
;
200 cdb
->ata_pass_thru
.protocol
= ATA_PROTO_PIO_DATA_IN
;
201 cdb
->ata_pass_thru
.flags
= ATA_FLG_T_DIR
|ATA_FLG_TLEN_STPSIU
;
202 cdb
->ata_pass_thru
.command
= ATA_IDENTIFY_DEVICE
;
205 cpt
.cam_flags
= CAM_DIR_IN
;
206 cpt
.cam_cdb_len
= 16;
207 cpt
.cam_dxfer_len
= 512;
208 cpt
.cam_data_ptr
= (uint32_t)data
;
209 cpt
.cam_sense_len
= sizeof(sense
);
210 cpt
.cam_sense_ptr
= (uint32_t)&sense
;
211 cdb
->ata_pass_thru
.opcode
= SC_ATA_PT16
;
212 cdb
->ata_pass_thru
.protocol
= ATA_PROTO_PIO_DATA_IN
;
213 cdb
->ata_pass_thru
.flags
= ATA_FLG_T_DIR
|ATA_FLG_TLEN_STPSIU
;
214 cdb
->ata_pass_thru
.command
= ATA_IDENTIFY_PACKET_DEVICE
;
217 cpt
.cam_flags
= CAM_DIR_NONE
;
218 cpt
.cam_cdb_len
= 16;
219 cpt
.cam_sense_len
= sizeof(sense
);
220 cpt
.cam_sense_ptr
= (uint32_t)&sense
;
221 cdb
->ata_pass_thru
.opcode
= SC_ATA_PT16
;
222 cdb
->ata_pass_thru
.protocol
= ATA_PROTO_DATA_NONE
;
223 cdb
->ata_pass_thru
.command
= ATA_SMART_CMD
;
224 cdb
->ata_pass_thru
.features
= ATA_SMART_ENABLE
;
225 cdb
->ata_pass_thru
.lba_mid
= ATA_SMART_LBA_MID_SIG
;
226 cdb
->ata_pass_thru
.lba_high
= ATA_SMART_LBA_HI_SIG
;
229 cpt
.cam_flags
= CAM_DIR_NONE
;
230 cpt
.cam_cdb_len
= 16;
231 cpt
.cam_sense_len
= sizeof(sense
);
232 cpt
.cam_sense_ptr
= (uint32_t)&sense
;
233 cdb
->ata_pass_thru
.opcode
= SC_ATA_PT16
;
234 cdb
->ata_pass_thru
.protocol
= ATA_PROTO_DATA_NONE
;
235 cdb
->ata_pass_thru
.command
= ATA_SMART_CMD
;
236 cdb
->ata_pass_thru
.features
= ATA_SMART_DISABLE
;
237 cdb
->ata_pass_thru
.lba_mid
= ATA_SMART_LBA_MID_SIG
;
238 cdb
->ata_pass_thru
.lba_high
= ATA_SMART_LBA_HI_SIG
;
241 // NOTE: According to ATAPI 4 and UP, this command is obsolete
242 cpt
.cam_flags
= CAM_DIR_NONE
;
243 cpt
.cam_cdb_len
= 16;
244 cpt
.cam_sense_len
= sizeof(sense
);
245 cpt
.cam_sense_ptr
= (uint32_t)&sense
;
246 cdb
->ata_pass_thru
.opcode
= SC_ATA_PT16
;
247 cdb
->ata_pass_thru
.protocol
= ATA_PROTO_DATA_NONE
;
248 cdb
->ata_pass_thru
.command
= ATA_SMART_CMD
;
249 cdb
->ata_pass_thru
.features
= ATA_SMART_AUTO_OFFLINE
;
250 cdb
->ata_pass_thru
.lba_low
= select
;
251 cdb
->ata_pass_thru
.lba_mid
= ATA_SMART_LBA_MID_SIG
;
252 cdb
->ata_pass_thru
.lba_high
= ATA_SMART_LBA_HI_SIG
;
255 cpt
.cam_flags
= CAM_DIR_NONE
;
256 cpt
.cam_cdb_len
= 16;
257 cpt
.cam_sense_len
= sizeof(sense
);
258 cpt
.cam_sense_ptr
= (uint32_t)&sense
;
259 cdb
->ata_pass_thru
.opcode
= SC_ATA_PT16
;
260 cdb
->ata_pass_thru
.protocol
= ATA_PROTO_DATA_NONE
;
261 cdb
->ata_pass_thru
.command
= ATA_SMART_CMD
;
262 cdb
->ata_pass_thru
.features
= ATA_SMART_AUTOSAVE
;
263 cdb
->ata_pass_thru
.sector_count
= select
;
264 cdb
->ata_pass_thru
.lba_mid
= ATA_SMART_LBA_MID_SIG
;
265 cdb
->ata_pass_thru
.lba_high
= ATA_SMART_LBA_HI_SIG
;
267 case IMMEDIATE_OFFLINE
:
268 // NOTE: According to ATAPI 4 and UP, this command is obsolete
269 cpt
.cam_flags
= CAM_DIR_NONE
;
270 cpt
.cam_cdb_len
= 16;
271 cpt
.cam_sense_len
= sizeof(sense
);
272 cpt
.cam_sense_ptr
= (uint32_t)&sense
;
273 cdb
->ata_pass_thru
.opcode
= SC_ATA_PT16
;
274 cdb
->ata_pass_thru
.protocol
= ATA_PROTO_DATA_NONE
;
275 cdb
->ata_pass_thru
.command
= ATA_SMART_CMD
;
276 cdb
->ata_pass_thru
.features
= ATA_SMART_IMMEDIATE_OFFLINE
;
277 cdb
->ata_pass_thru
.lba_low
= select
;
278 cdb
->ata_pass_thru
.lba_mid
= ATA_SMART_LBA_MID_SIG
;
279 cdb
->ata_pass_thru
.lba_high
= ATA_SMART_LBA_HI_SIG
;
282 // same command, no HDIO in NetBSD
284 cpt
.cam_flags
= CAM_DIR_NONE
;
285 cpt
.cam_cdb_len
= 16;
286 cpt
.cam_sense_len
= sizeof(sense
);
287 cpt
.cam_sense_ptr
= (uint32_t)&sense
;
288 cdb
->ata_pass_thru
.opcode
= SC_ATA_PT16
;
289 cdb
->ata_pass_thru
.protocol
= ATA_PROTO_DATA_NONE
;
290 cdb
->ata_pass_thru
.flags
= ATA_FLG_CK_COND
;
291 cdb
->ata_pass_thru
.command
= ATA_SMART_CMD
;
292 cdb
->ata_pass_thru
.features
= ATA_SMART_STATUS
;
293 cdb
->ata_pass_thru
.lba_mid
= ATA_SMART_LBA_MID_SIG
;
294 cdb
->ata_pass_thru
.lba_high
= ATA_SMART_LBA_HI_SIG
;
296 case CHECK_POWER_MODE
:
297 cpt
.cam_flags
= CAM_DIR_NONE
;
298 cpt
.cam_cdb_len
= 16;
299 cpt
.cam_sense_len
= sizeof(sense
);
300 cpt
.cam_sense_ptr
= (uint32_t)&sense
;
301 cdb
->ata_pass_thru
.opcode
= SC_ATA_PT16
;
302 cdb
->ata_pass_thru
.protocol
= ATA_PROTO_DATA_NONE
;
303 cdb
->ata_pass_thru
.flags
= ATA_FLG_CK_COND
;
304 cdb
->ata_pass_thru
.command
= ATA_CHECK_POWER_MODE
;
307 pout("Unrecognized command %d in ata_command_interface()\n", command
);
312 if((status
=ata_pass_thru(fd
,&cpt
))==EOK
)
315 if(cpt
.cam_status
!=CAM_REQ_CMP
)
317 ata_interpret_sense(&cpt
,&sense
,&status
,0);
318 if(command
==STATUS
||command
==STATUS_CHECK
)
319 rc
=((sense
.desc
.lba_high
<<8)|sense
.desc
.lba_mid
)==ATA_SMART_SIG
?0:1;
322 if(command
==CHECK_POWER_MODE
)
323 data
[0]=cdb
->ata_pass_thru
.sector_count
;
327 //----------------------------------------------------------------------------------------------
328 // Interface to SCSI devices. See os_linux.c
329 int do_scsi_cmnd_io(int fd
,struct scsi_cmnd_io
* iop
,int report
)
336 //----------------------------------------------------------------------------------------------
337 //----------------------------------------------------------------------------------------------
338 static int ata_sense_data(void *sdata
,int *error
,int *key
,int *asc
,int *ascq
)
341 SCSI_SENSE_DESCRIPTOR
*sd
;
342 sf
=(SCSI_SENSE
*)sdata
;
343 sd
=(SCSI_SENSE_DESCRIPTOR
*)sdata
;
345 if(*error
& SENSE_DATA_FMT_DESCRIPTOR
)
347 *key
=sd
->sense
& SK_MSK
;
353 *key
=sf
->sense
& SK_MSK
;
359 //----------------------------------------------------------------------------------------------
360 static int ata_interpret_sense(struct cam_pass_thru
*cpt
,void *sense
,int *status
,int rcount
)
369 if(cpt
->cam_status
&CAM_AUTOSNS_VALID
)
371 ata_sense_data(sense
,&error
,&key
,&asc
,&ascq
);
374 case SK_NO_SENSE
: // No sense data (no error)
378 case SK_RECOVERED
: // Recovered error
381 case ASC_ATA_PASS_THRU
:
384 case ASCQ_ATA_PASS_THRU_INFO_AVAIL
:
396 case SK_NOT_RDY
: // Device not ready
403 case ASCQ_BECOMING_READY
:
404 case ASCQ_CAUSE_NOT_REPORTABLE
:
410 case ASC_MEDIA_NOT_PRESENT
:
416 case SK_MEDIUM
: // Medium error
417 case SK_HARDWARE
: // Hardware error
421 case SK_ILLEGAL
: // Illegal Request (bad command)
425 case SK_UNIT_ATN
: // Unit Attention
428 case ASC_MEDIUM_CHANGED
:
436 case SK_DATA_PROT
: // Data Protect
440 case SK_VENDOR
: // Vendor Specific
441 case SK_CPY_ABORT
: // Copy Aborted
445 case SK_CMD_ABORT
: // Aborted Command
449 case SK_EQUAL
: // Equal
450 case SK_VOL_OFL
: // Volume Overflow
451 case SK_MISCMP
: // Miscompare
452 case SK_RESERVED
: // Reserved
457 switch(cpt
->cam_status
&CAM_STATUS_MASK
)
459 case CAM_REQ_CMP_ERR
: // CCB request completed with an err
463 case CAM_BUSY
: // CAM subsystem is busy
466 case CAM_REQ_INVALID
: // CCB request is invalid
467 case CAM_PATH_INVALID
: // Path ID supplied is invalid
468 case CAM_DEV_NOT_THERE
: // SCSI device not installed/there
469 case CAM_SEL_TIMEOUT
: // Target selection timeout
470 case CAM_LUN_INVALID
: // LUN supplied is invalid
471 case CAM_TID_INVALID
: // Target ID supplied is invalid
475 case CAM_CMD_TIMEOUT
: // Command timeout
476 *status
=rcount
?EAGAIN
:EIO
;
478 case CAM_MSG_REJECT_REC
: // Message reject received
479 case CAM_SCSI_BUS_RESET
: // SCSI bus reset sent/received
480 case CAM_UNCOR_PARITY
: // Uncorrectable parity err occurred
481 case CAM_AUTOSENSE_FAIL
: // Autosense: Request sense cmd fail
482 case CAM_NO_HBA
: // No HBA detected Error
483 case CAM_DATA_RUN_ERR
: // Data overrun/underrun error
487 case CAM_UNEXP_BUSFREE
: // Unexpected BUS free
488 case CAM_SEQUENCE_FAIL
: // Target bus phase sequence failure
491 case CAM_PROVIDE_FAIL
: // Unable to provide requ. capability
495 case CAM_CCB_LEN_ERR
: // CCB length supplied is inadequate
496 case CAM_BDR_SENT
: // A SCSI BDR msg was sent to target
497 case CAM_REQ_TERMIO
: // CCB request terminated by the host
498 case CAM_FUNC_NOTAVAIL
: // The requ. func is not available
499 case CAM_NO_NEXUS
: // Nexus is not established
500 case CAM_IID_INVALID
: // The initiator ID is invalid
501 case CAM_CDB_RECVD
: // The SCSI CDB has been received
505 case CAM_SCSI_BUSY
: // SCSI bus busy
513 //----------------------------------------------------------------------------------------------
514 static int ata_pass_thru(int fd
,struct cam_pass_thru
*pcpt
)
519 struct cam_pass_thru cpt
;
522 SETIOV(&iov
[0],&cpt
,sizeof(cpt
));
523 cpt
.cam_timeout
=cpt
.cam_timeout
?cpt
.cam_timeout
:CAM_TIME_DEFAULT
;
524 if(cpt
.cam_sense_len
)
526 SETIOV(&iov
[1],(void *)cpt
.cam_sense_ptr
,cpt
.cam_sense_len
);
527 cpt
.cam_sense_ptr
=sizeof(cpt
);
530 if(cpt
.cam_dxfer_len
)
532 SETIOV(&iov
[2],(void *)cpt
.cam_data_ptr
,cpt
.cam_dxfer_len
);
533 cpt
.cam_data_ptr
=(paddr_t
)sizeof(cpt
)+cpt
.cam_sense_len
;
536 if((status
=devctlv(fd
,DCMD_CAM_PASS_THRU
,icnt
,icnt
,iov
,iov
,NULL
)))
537 pout("ata_pass_thru devctl: %s\n",strerror(status
));
538 pcpt
->cam_status
=cpt
.cam_status
;
539 pcpt
->cam_scsi_status
=cpt
.cam_scsi_status
;
542 //----------------------------------------------------------------------------------------------