smartmontools  SVN Rev 4430
Utility to control and monitor storage systems with "S.M.A.R.T."
os_os2.cpp
Go to the documentation of this file.
1 /*
2  * os_os2.c
3  *
4  * Home page of code is: http://www.smartmontools.org
5  *
6  * Copyright (C) 2004-8 Yuri Dario <smartmontools-support@lists.sourceforge.net>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2, or (at your option)
11  * any later version.
12  *
13  * You should have received a copy of the GNU General Public License
14  * (for example COPYING); if not, write to the Free Software Foundation,
15  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  */
17 
18 /*
19  *
20  * Thanks to Daniela Engert for providing sample code for SMART ioctl access.
21  *
22  */
23 
24 // These are needed to define prototypes for the functions defined below
25 #include "config.h"
26 #include "int64.h"
27 
28 #include <ctype.h>
29 #include <errno.h>
30 #include "atacmds.h"
31 #include "scsicmds.h"
32 #include "utility.h"
33 
34 // This is to include whatever prototypes you define in os_generic.h
35 #include "os_os2.h"
36 
37 // Needed by '-V' option (CVS versioning) of smartd/smartctl
38 const char *os_XXXX_c_cvsid="$Id: os_os2.cpp 4423 2017-04-23 19:14:02Z samm2 $" \
40 
41 // global handle to device driver
42 static HFILE hDevice;
43 
44 // print examples for smartctl. You should modify this function so
45 // that the device paths are sensible for your OS, and to eliminate
46 // unsupported commands (eg, 3ware controllers).
48  printf("=================================================== SMARTCTL EXAMPLES =====\n\n");
49 #ifdef HAVE_GETOPT_LONG
50  printf(
51  " smartctl -a hd0 (Prints all SMART information)\n\n"
52  " smartctl --smart=on --offlineauto=on --saveauto=on hd0\n"
53  " (Enables SMART on first disk)\n\n"
54  " smartctl -t long hd0 (Executes extended disk self-test)\n\n"
55  " smartctl --attributes --log=selftest --quietmode=errorsonly hd0\n"
56  " (Prints Self-Test & Attribute errors)\n"
57  );
58 #else
59  printf(
60  " smartctl -a hd0 (Prints all SMART on first disk with DANIS506)\n"
61  " smartctl -a ahci0 (Prints all SMART on first disk with OS2AHCI)\n"
62  " smartctl -s on -o on -S on hd0 (Enables SMART on first disk)\n"
63  " smartctl -t long hd0 (Executes extended disk self-test)\n"
64  " smartctl -A -l selftest -q errorsonly hd0\n"
65  " (Prints Self-Test & Attribute errors)\n"
66  );
67 #endif
68  return;
69 }
70 
71 static const char * skipdev(const char * s)
72 {
73  return (!strncmp(s, "/dev/", 5) ? s + 5 : s);
74 }
75 
76 // tries to guess device type given the name (a path). See utility.h
77 // for return values.
78 int guess_device_type (const char* dev_name) {
79 
80  //printf( "dev_name %s\n", dev_name);
81  dev_name = skipdev(dev_name);
82  if (!strncmp(dev_name, "hd", 2) || !strncmp(dev_name, "ahci", 4))
83  return CONTROLLER_ATA;
84  return CONTROLLER_UNKNOWN;
85 }
86 
87 // makes a list of ATA or SCSI devices for the DEVICESCAN directive of
88 // smartd. Returns number N of devices, or -1 if out of
89 // memory. Allocates N+1 arrays: one of N pointers (devlist); the
90 // other N arrays each contain null-terminated character strings. In
91 // the case N==0, no arrays are allocated because the array of 0
92 // pointers has zero length, equivalent to calling malloc(0).
93 
94 int make_device_names (char*** devlist, const char* name) {
95 
96  int result;
97  int index;
98  const int max_dev = 32; // scan only first 32 devices
99 
100  // SCSI is not supported
101  if (strcmp (name, "ATA") != 0)
102  return 0;
103 
104  // try to open DANIS
105  APIRET rc;
106  ULONG ActionTaken;
107  HFILE danisDev, ahciDev;
108  bool is_danis = 0, is_ahci = 0;
109 
110  rc = DosOpen ((const char unsigned *)danisdev, &danisDev, &ActionTaken, 0, FILE_SYSTEM,
111  OPEN_ACTION_OPEN_IF_EXISTS, OPEN_SHARE_DENYNONE |
112  OPEN_FLAGS_NOINHERIT | OPEN_ACCESS_READONLY, NULL);
113  if (!rc)
114  is_danis = 1;
115 
116  rc = DosOpen ((const char unsigned *)ahcidev, &ahciDev, &ActionTaken, 0, FILE_SYSTEM,
117  OPEN_ACTION_OPEN_IF_EXISTS, OPEN_SHARE_DENYNONE |
118  OPEN_FLAGS_NOINHERIT | OPEN_ACCESS_READONLY, NULL);
119  if (!rc)
120  is_ahci = 1;
121 
122  // Count the devices.
123  result = 0;
124 
126  ULONG PLen = 1;
127  ULONG IDLen = 512;
128  struct ata_identify_device Id;
129 
130  for(int i = 0; i < max_dev; i++) {
131  if (is_ahci) {
132  Parms.byPhysicalUnit = i;
133  rc = DosDevIOCtl (ahciDev, DSKSP_CAT_GENERIC, DSKSP_GET_INQUIRY_DATA,
134  (PVOID)&Parms, PLen, &PLen, (PVOID)&Id, IDLen, &IDLen);
135  if (!rc) result++;
136  }
137  if (is_danis) {
138  Parms.byPhysicalUnit = i + 0x80;
139  rc = DosDevIOCtl (danisDev, DSKSP_CAT_GENERIC, DSKSP_GET_INQUIRY_DATA,
140  (PVOID)&Parms, PLen, &PLen, (PVOID)&Id, IDLen, &IDLen);
141  if (!rc) result++;
142  }
143  }
144  *devlist = (char**)calloc (result, sizeof (char *));
145  if (! *devlist)
146  goto error;
147  index = 0;
148 
149  // add devices
150  for(int i = 0; i < max_dev; i++) {
151  if (is_ahci) {
152  Parms.byPhysicalUnit = i;
153  rc = DosDevIOCtl (ahciDev, DSKSP_CAT_GENERIC, DSKSP_GET_INQUIRY_DATA,
154  (PVOID)&Parms, PLen, &PLen, (PVOID)&Id, IDLen, &IDLen);
155  if (!rc) {
156  asprintf(&(*devlist)[index], "ahci%d", i);
157  if (! (*devlist)[index])
158  goto error;
159  index++;
160  }
161  }
162  if (is_danis) {
163  Parms.byPhysicalUnit = i + 0x80;
164  rc = DosDevIOCtl (danisDev, DSKSP_CAT_GENERIC, DSKSP_GET_INQUIRY_DATA,
165  (PVOID)&Parms, PLen, &PLen, (PVOID)&Id, IDLen, &IDLen);
166  if (!rc) {
167  asprintf(&(*devlist)[index], "hd%d", i);
168  if (! (*devlist)[index])
169  goto error;
170  index++;
171  }
172  }
173  }
174 
175  if (is_danis)
176  DosClose( danisDev);
177 
178  if (is_ahci)
179  DosClose( ahciDev);
180 
181  return result;
182 
183  error:
184  if (*devlist)
185  {
186  for (index = 0; index < result; index++)
187  if ((*devlist)[index])
188  free ((*devlist)[index]);
189  free (*devlist);
190  }
191  if (is_danis)
192  DosClose( danisDev);
193 
194  if (is_ahci)
195  DosClose( ahciDev);
196 
197  return -1;
198 }
199 
200 // Like open(). Return non-negative integer handle, only used by the
201 // functions below. type=="ATA" or "SCSI". If you need to store
202 // extra information about your devices, create a private internal
203 // array within this file (see os_freebsd.cpp for an example). If you
204 // can not open the device (permission denied, does not exist, etc)
205 // set errno as open() does and return <0.
206 int deviceopen(const char *pathname, char * /* type */ ){
207 
208  int fd = 0;
209  APIRET rc;
210  ULONG ActionTaken;
211 
212  char * activedev = NULL;
213 
214  pathname = skipdev(pathname);
215  // DANIS506 driver
216  if(strlen(pathname) > strlen(danispref)
217  && strncmp(pathname, danispref, strlen(danispref)) == 0) {
218  fd = strtol(pathname + strlen(danispref), NULL, 10) + 0x80;
219  activedev = (char *)danisdev;
220  }
221  // OS2AHCI driver
222  if(strlen(pathname) > strlen(ahcipref)
223  && strncmp(pathname, ahcipref, strlen(ahcipref)) == 0) {
224  fd = strtol(pathname + strlen(ahcipref), NULL, 10);
225  activedev = (char *)ahcidev;
226  }
227 
228  if(!activedev) {
229  pout("Error: please specify hdX or ahciX device name\n");
230  return -1;
231  }
232  //printf( "deviceopen pathname %s\n", pathname);
233  rc = DosOpen ((const char unsigned *)activedev, &hDevice, &ActionTaken, 0, FILE_SYSTEM,
234  OPEN_ACTION_OPEN_IF_EXISTS, OPEN_SHARE_DENYNONE |
235  OPEN_FLAGS_NOINHERIT | OPEN_ACCESS_READONLY, NULL);
236  if (rc) {
237  char errmsg[256];
238  snprintf(errmsg,256,"Smartctl open driver %s failed (%lu)", activedev, rc);
239  errmsg[255]='\0';
240  syserror(errmsg);
241  return -1;
242  }
243 
244  return fd;
245 }
246 
247 // Like close(). Acts only on integer handles returned by
248 // deviceopen() above.
249 int deviceclose(int /* fd */){
250 
251  DosClose( hDevice);
252  hDevice = NULL;
253 
254  return 0;
255 }
256 
257 //
258 // OS/2 direct ioctl interface to IBMS506$/OS2AHCI$
259 //
260 static int dani_ioctl( int device, void* arg)
261 {
262  unsigned char* buff = (unsigned char*) arg;
263  APIRET rc;
265  ULONG PLen = 1;
266  ULONG DLen = 512; //sizeof (*buf);
267  ULONG value = 0;
268 
269  // printf( "device %d, request 0x%x, arg[0] 0x%x, arg[2] 0x%x\n", device, request, buff[0], buff[2]);
270 
271  Parms.byPhysicalUnit = device;
272  switch( buff[0]) {
273  case ATA_IDENTIFY_DEVICE:
275  (PVOID)&Parms, PLen, &PLen, (UCHAR *)arg+4, DLen, &DLen);
276  if (rc != 0)
277  {
278  printf ("DANIS506 ATA DSKSP_GET_INQUIRY_DATA failed (%lu)\n", rc);
279  return -1;
280  }
281  break;
282  case ATA_SMART_CMD:
283  switch( buff[2]) {
284  case ATA_SMART_STATUS:
285  DLen = sizeof(value);
286  // OS/2 already checks CL/CH in IBM1S506 code!! see s506rte.c (ddk)
287  // value: -1=not supported, 0=ok, 1=failing
288  rc = DosDevIOCtl (hDevice, DSKSP_CAT_SMART, DSKSP_SMART_GETSTATUS,
289  (PVOID)&Parms, PLen, &PLen, (PVOID)&value, DLen, &DLen);
290  if (rc)
291  {
292  printf ("DANIS506 ATA GET SMART_STATUS failed (%lu)\n", rc);
293  return -1;
294  }
295  buff[4] = (unsigned char)value;
296  break;
299  (PVOID)&Parms, PLen, &PLen, (UCHAR *)arg+4, DLen, &DLen);
300  if (rc)
301  {
302  printf ("DANIS506 ATA GET DSKSP_SMART_GET_ATTRIBUTES failed (%lu)\n", rc);
303  return -1;
304  }
305  break;
308  (PVOID)&Parms, PLen, &PLen, (UCHAR *)arg+4, DLen, &DLen);
309  if (rc)
310  {
311  printf ("DANIS506 ATA GET DSKSP_SMART_GET_THRESHOLDS failed (%lu)\n", rc);
312  return -1;
313  }
314  break;
316  buff[4] = buff[1]; // copy select field
317  rc = DosDevIOCtl (hDevice, DSKSP_CAT_SMART, DSKSP_SMART_GET_LOG,
318  (PVOID)&Parms, PLen, &PLen, (UCHAR *)arg+4, DLen, &DLen);
319  if (rc)
320  {
321  printf ("DANIS506 ATA GET DSKSP_SMART_GET_LOG failed (%lu)\n", rc);
322  return -1;
323  }
324  break;
325  case ATA_SMART_ENABLE:
326  buff[0] = 1; // enable
327  DLen = 1;
328  rc = DosDevIOCtl (hDevice, DSKSP_CAT_SMART, DSKSP_SMART_ONOFF,
329  (PVOID)&Parms, PLen, &PLen, (PVOID)buff, DLen, &DLen);
330  if (rc) {
331  printf ("DANIS506 ATA GET DSKSP_SMART_ONOFF failed (%lu)\n", rc);
332  return -1;
333  }
334  break;
335  case ATA_SMART_DISABLE:
336  buff[0] = 0; // disable
337  DLen = 1;
338  rc = DosDevIOCtl (hDevice, DSKSP_CAT_SMART, DSKSP_SMART_ONOFF,
339  (PVOID)&Parms, PLen, &PLen, (PVOID)buff, DLen, &DLen);
340  if (rc) {
341  printf ("DANIS506 ATA GET DSKSP_SMART_ONOFF failed (%lu)\n", rc);
342  return -1;
343  }
344  break;
345 #if 0
347  buff[0] = buff[3]; // select field
348  DLen = 1;
350  (PVOID)&Parms, PLen, &PLen, (PVOID)buff, DLen, &DLen);
351  if (rc) {
352  printf ("DANIS506 ATA GET DSKSP_SMART_ONOFF failed (%lu)\n", rc);
353  return -1;
354  }
355  break;
356 #endif
357  case ATA_SMART_AUTOSAVE:
358  buff[0] = buff[3]; // select field
359  DLen = 1;
361  (PVOID)&Parms, PLen, &PLen, (PVOID)buff, DLen, &DLen);
362  if (rc) {
363  printf ("DANIS506 ATA DSKSP_SMART_AUTOSAVE_ONOFF failed (%lu)\n", rc);
364  return -1;
365  }
366  break;
368  buff[0] = buff[1]; // select field
369  DLen = 1;
371  (PVOID)&Parms, PLen, &PLen, (PVOID)buff, DLen, &DLen);
372  if (rc) {
373  printf ("DANIS506 ATA GET DSKSP_SMART_EXEC_OFFLINE failed (%lu)\n", rc);
374  return -1;
375  }
376  break;
377 
378  default:
379  fprintf( stderr, "device %d, arg[0] 0x%x, arg[2] 0x%x\n", device, buff[0], buff[2]);
380  fprintf( stderr, "unknown ioctl\n");
381  return -1;
382  break;
383  }
384  break;
385  //case WIN_PIDENTIFY:
386  // break;
387  default:
388  fprintf( stderr, "unknown ioctl\n");
389  return -1;
390  break;
391  }
392 
393  // ok
394  return 0;
395 }
396 
397 // Interface to ATA devices. See os_linux.cpp for the cannonical example.
398 // DETAILED DESCRIPTION OF ARGUMENTS
399 // device: is the integer handle provided by deviceopen()
400 // command: defines the different operations, see atacmds.h
401 // select: additional input data IF NEEDED (which log, which type of
402 // self-test).
403 // data: location to write output data, IF NEEDED (1 or 512 bytes).
404 // Note: not all commands use all arguments.
405 // RETURN VALUES (for all commands BUT command==STATUS_CHECK)
406 // -1 if the command failed
407 // 0 if the command succeeded,
408 // RETURN VALUES if command==STATUS_CHECK
409 // -1 if the command failed OR the disk SMART status can't be determined
410 // 0 if the command succeeded and disk SMART status is "OK"
411 // 1 if the command succeeded and disk SMART status is "FAILING"
412 
413 // huge value of buffer size needed because HDIO_DRIVE_CMD assumes
414 // that buff[3] is the data size. Since the ATA_SMART_AUTOSAVE and
415 // ATA_SMART_AUTO_OFFLINE use values of 0xf1 and 0xf8 we need the space.
416 // Otherwise a 4+512 byte buffer would be enough.
417 #define STRANGE_BUFFER_LENGTH (4+512*0xf8)
418 
419 int ata_command_interface(int device, smart_command_set command, int select, char *data){
420  unsigned char buff[STRANGE_BUFFER_LENGTH];
421  // positive: bytes to write to caller. negative: bytes to READ from
422  // caller. zero: non-data command
423  int copydata=0;
424 
425  const int HDIO_DRIVE_CMD_OFFSET = 4;
426 
427  // See struct hd_drive_cmd_hdr in hdreg.h. Before calling ioctl()
428  // buff[0]: ATA COMMAND CODE REGISTER
429  // buff[1]: ATA SECTOR NUMBER REGISTER == LBA LOW REGISTER
430  // buff[2]: ATA FEATURES REGISTER
431  // buff[3]: ATA SECTOR COUNT REGISTER
432 
433  // Note that on return:
434  // buff[2] contains the ATA SECTOR COUNT REGISTER
435 
436  // clear out buff. Large enough for HDIO_DRIVE_CMD (4+512 bytes)
437  memset(buff, 0, STRANGE_BUFFER_LENGTH);
438 
439  //printf( "command, select %d,%d\n", command, select);
440  buff[0]=ATA_SMART_CMD;
441  switch (command){
442  case CHECK_POWER_MODE:
443  buff[0]=ATA_CHECK_POWER_MODE;
444  copydata=1;
445  break;
446  case READ_VALUES:
447  buff[2]=ATA_SMART_READ_VALUES;
448  buff[3]=1;
449  copydata=512;
450  break;
451  case READ_THRESHOLDS:
453  buff[1]=buff[3]=1;
454  copydata=512;
455  break;
456  case READ_LOG:
458  buff[1]=select;
459  buff[3]=1;
460  copydata=512;
461  break;
462  case WRITE_LOG:
463  break;
464  case IDENTIFY:
465  buff[0]=ATA_IDENTIFY_DEVICE;
466  buff[3]=1;
467  copydata=512;
468  break;
469  case PIDENTIFY:
471  buff[3]=1;
472  copydata=512;
473  break;
474  case ENABLE:
475  buff[2]=ATA_SMART_ENABLE;
476  buff[1]=1;
477  break;
478  case DISABLE:
479  buff[2]=ATA_SMART_DISABLE;
480  buff[1]=1;
481  break;
482  case STATUS:
483  case STATUS_CHECK:
484  // this command only says if SMART is working. It could be
485  // replaced with STATUS_CHECK below.
486  buff[2]=ATA_SMART_STATUS;
487  buff[4]=0;
488  break;
489  case AUTO_OFFLINE:
490  buff[2]=ATA_SMART_AUTO_OFFLINE;
491  buff[3]=select; // YET NOTE - THIS IS A NON-DATA COMMAND!!
492  break;
493  case AUTOSAVE:
494  buff[2]=ATA_SMART_AUTOSAVE;
495  buff[3]=select; // YET NOTE - THIS IS A NON-DATA COMMAND!!
496  break;
497  case IMMEDIATE_OFFLINE:
499  buff[1]=select;
500  break;
501  //case STATUS_CHECK:
502  // // This command uses HDIO_DRIVE_TASK and has different syntax than
503  // // the other commands.
504  // buff[1]=ATA_SMART_STATUS;
505  // break;
506  default:
507  pout("Unrecognized command %d in linux_ata_command_interface()\n"
508  "Please contact " PACKAGE_BUGREPORT "\n", command);
509  errno=ENOSYS;
510  return -1;
511  }
512 
513  // We are now calling ioctl wrapper to the driver.
514  // TODO: use PASSTHRU in case of OS2AHCI driver
515  if ((dani_ioctl(device, buff)))
516  return -1;
517 
518  // There are two different types of ioctls(). The HDIO_DRIVE_TASK
519  // one is this:
520  if (command==STATUS_CHECK){
521  // Cyl low and Cyl high unchanged means "Good SMART status"
522  if (buff[4]==0)
523  return 0;
524 
525  // These values mean "Bad SMART status"
526  if (buff[4]==1)
527  return 1;
528 
529  // We haven't gotten output that makes sense; print out some debugging info
530  syserror("Error SMART Status command failed");
531  pout("Please get assistance from " PACKAGE_HOMEPAGE "\n");
532  return -1;
533  }
534 
535  // CHECK POWER MODE command returns information in the Sector Count
536  // register (buff[3]). Copy to return data buffer.
537  if (command==CHECK_POWER_MODE)
538  buff[HDIO_DRIVE_CMD_OFFSET]=buff[2];
539 
540  // if the command returns data then copy it back
541  if (copydata)
542  memcpy(data, buff+HDIO_DRIVE_CMD_OFFSET, copydata);
543 
544  return 0;
545 }
546 
547 // Interface to SCSI devices. N/A under OS/2
548 int do_scsi_cmnd_io(int /* fd */, struct scsi_cmnd_io * /* iop */, int /* report */) {
549  pout("SCSI interface is not implemented\n");
550  return -ENOSYS;
551 }
#define ATA_SMART_READ_LOG_SECTOR
Definition: atacmds.h:105
u16 s[6]
Definition: megaraid.h:97
#define ATACMDS_H_CVSID
Definition: atacmds.h:28
#define ATA_SMART_CMD
Definition: atacmds.h:75
static HFILE hDevice
Definition: os_os2.cpp:42
int deviceopen(const char *pathname, char *)
Definition: os_os2.cpp:206
#define ATA_SMART_DISABLE
Definition: atacmds.h:109
const char * os_XXXX_c_cvsid
Definition: os_os2.cpp:38
int do_scsi_cmnd_io(int, struct scsi_cmnd_io *, int)
Definition: os_os2.cpp:548
#define ATA_SMART_AUTOSAVE
Definition: atacmds.h:102
#define snprintf
Definition: utility.h:68
#define DSKSP_SMART_GET_ATTRIBUTES
Definition: os_os2.h:41
int ata_command_interface(int device, smart_command_set command, int select, char *data)
Definition: os_os2.cpp:419
#define ATA_IDENTIFY_DEVICE
Definition: atacmds.h:72
#define ATA_IDENTIFY_PACKET_DEVICE
Definition: atacmds.h:73
#define SCSICMDS_H_CVSID
Definition: scsicmds.h:33
ptr_t data
Definition: megaraid.h:94
#define DSKSP_SMART_GET_LOG
Definition: os_os2.h:43
#define ATA_CHECK_POWER_MODE
Definition: atacmds.h:71
#define DSKSP_SMART_ONOFF
Definition: os_os2.h:37
void syserror(const char *message)
Definition: utility.cpp:360
#define OS_XXXX_H_CVSID
Definition: os_os2.h:21
void pout(const char *fmt,...)
Definition: smartctl.cpp:1196
#define DSKSP_CAT_SMART
Definition: os_os2.h:36
int deviceclose(int)
Definition: os_os2.cpp:249
#define ATA_SMART_READ_VALUES
Definition: atacmds.h:100
#define DSKSP_SMART_GET_THRESHOLDS
Definition: os_os2.h:42
#define DSKSP_SMART_EXEC_OFFLINE
Definition: os_os2.h:45
Definition: atacmds.h:55
#define ATA_SMART_AUTO_OFFLINE
Definition: atacmds.h:113
#define DSKSP_SMART_AUTO_OFFLINE
Definition: os_os2.h:44
#define DSKSP_CAT_GENERIC
Definition: os_os2.h:50
smart_command_set
Definition: atacmds.h:48
void print_smartctl_examples()
Definition: os_os2.cpp:47
int guess_device_type(const char *dev_name)
Definition: os_os2.cpp:78
#define ATA_SMART_READ_THRESHOLDS
Definition: atacmds.h:101
const char * danisdev
Definition: os_os2.h:68
#define ATA_SMART_IMMEDIATE_OFFLINE
Definition: atacmds.h:104
#define DSKSP_SMART_GETSTATUS
Definition: os_os2.h:40
const char * ahcidev
Definition: os_os2.h:70
int make_device_names(char ***devlist, const char *name)
Definition: os_os2.cpp:94
#define STRANGE_BUFFER_LENGTH
Definition: os_os2.cpp:417
static int dani_ioctl(int device, void *arg)
Definition: os_os2.cpp:260
#define ATA_SMART_ENABLE
Definition: atacmds.h:108
#define DSKSP_GET_INQUIRY_DATA
Definition: os_os2.h:51
#define DSKSP_SMART_AUTOSAVE_ONOFF
Definition: os_os2.h:38
const char * ahcipref
Definition: os_os2.h:71
Definition: atacmds.h:50
static const char * skipdev(const char *s)
Definition: os_os2.cpp:71
const char * danispref
Definition: os_os2.h:69
#define UTILITY_H_CVSID
Definition: utility.h:28
#define ATA_SMART_STATUS
Definition: atacmds.h:110