Annotation of embedaddon/smartmontools/os_solaris.cpp, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * os_solaris.c
                      3:  *
                      4:  * Home page of code is: http://smartmontools.sourceforge.net
                      5:  *
                      6:  * Copyright (C) 2003-8 SAWADA Keiji <smartmontools-support@lists.sourceforge.net>
                      7:  * Copyright (C) 2003-8 Casper Dik <smartmontools-support@lists.sourceforge.net>
                      8:  *
                      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)
                     12:  * any later version.
                     13:  *
                     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.
                     17:  *
                     18:  */
                     19: 
                     20: #include <stdlib.h>
                     21: #include <ctype.h>
                     22: #include <string.h>
                     23: #include <dirent.h>
                     24: #include <stdio.h>
                     25: #include <unistd.h>
                     26: #include <sys/param.h>
                     27: 
                     28: // These are needed to define prototypes for the functions defined below
                     29: #include "config.h"
                     30: #include "int64.h"
                     31: #include "atacmds.h"
                     32: #include "scsicmds.h"
                     33: #include "utility.h"
                     34: 
                     35: // This is to include whatever prototypes you define in os_solaris.h
                     36: #include "os_solaris.h"
                     37: 
                     38: #define ARGUSED(x) ((void)(x))
                     39: 
                     40: extern long long bytes;
                     41: 
                     42: static const char *filenameandversion="$Id: os_solaris.cpp,v 1.32 2008/06/12 21:46:31 ballen4705 Exp $";
                     43: 
                     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;
                     46: 
                     47: // The printwarning() function warns about unimplemented functions
                     48: int printedout[2];
                     49: char *unimplemented[2]={
                     50:   "ATA command routine ata_command_interface()",
                     51:   "3ware Escalade Controller command routine escalade_command_interface()",
                     52: };
                     53: 
                     54: int printwarning(int which){
                     55:   if (!unimplemented[which])
                     56:     return 0;
                     57: 
                     58:   if (printedout[which])
                     59:     return 1;
                     60:   
                     61:   printedout[which]=1;
                     62:   
                     63:   pout("\n"
                     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"
                     69:        "\n",
                     70:        unimplemented[which]);
                     71: 
                     72:   return 1;
                     73: }
                     74: 
                     75: // print examples for smartctl
                     76: void print_smartctl_examples(){
                     77:   printf("=================================================== SMARTCTL EXAMPLES =====\n\n");
                     78: #ifdef HAVE_GETOPT_LONG
                     79:   printf(
                     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"
                     86:          );
                     87: #else
                     88:   printf(
                     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"
                     94:          );
                     95: #endif
                     96:   return;
                     97: }
                     98: 
                     99: static const char *uscsidrvrs[] = {
                    100:         "sd",
                    101:         "ssd",
                    102:         "st"
                    103: };
                    104: 
                    105: static const char *atadrvrs[] = {
                    106:         "cmdk",
                    107:         "dad",
                    108: };
                    109: 
                    110: static int
                    111: isdevtype(const char *dev_name, const char *table[], int tsize)
                    112: {
                    113:   char devpath[MAXPATHLEN];
                    114:   int i;
                    115:   char *basename;
                    116: 
                    117:   if (realpath(dev_name, devpath) == NULL)
                    118:     return 0;
                    119:  
                    120:   if ((basename = strrchr(devpath, '/')) == NULL)
                    121:     return 0;
                    122: 
                    123:   basename++;
                    124: 
                    125:   for (i = 0; i < tsize; i++) {
                    126:     int l = strlen(table[i]);
                    127:     if (strncmp(basename, table[i], l) == 0 && basename[l] == '@')
                    128:       return 1;
                    129:   }
                    130:   return 0;
                    131: }
                    132: 
                    133: static int
                    134: isscsidev(const char *path)
                    135: {
                    136:   return isdevtype(path, uscsidrvrs, sizeof (uscsidrvrs) / sizeof (char *));
                    137: }
                    138: 
                    139: static int
                    140: isatadev(const char *path)
                    141: {
                    142:   return isdevtype(path, atadrvrs, sizeof (atadrvrs) / sizeof (char *));
                    143: }
                    144: 
                    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;
                    151:   else
                    152:     return CONTROLLER_UNKNOWN;
                    153: }
                    154: 
                    155: struct pathlist {
                    156:         char **names;
                    157:         int  nnames;
                    158:         int  maxnames;
                    159: };
                    160: 
                    161: static int
                    162: addpath(const char *path, struct pathlist *res)
                    163: {
                    164:         if (++res->nnames > res->maxnames) {
                    165:                 res->maxnames += 16;
                    166:                 res->names = static_cast<char**>(realloc(res->names, res->maxnames * sizeof (char *)));
                    167:                 if (res->names == NULL)
                    168:                         return -1;
                    169:                 bytes += 16*sizeof(char *);
                    170:         }
                    171:         if (!(res->names[res->nnames-1] = CustomStrDup((char *)path, 1, __LINE__, filenameandversion)))
                    172:                 return -1;
                    173:         return 0;
                    174: }
                    175: 
                    176: static int 
                    177: grokdir(const char *dir, struct pathlist *res, int testfun(const char *))
                    178: {
                    179:         char pathbuf[MAXPATHLEN];
                    180:         size_t len;
                    181:         DIR *dp;
                    182:         struct dirent *de;
                    183:         int isdisk = strstr(dir, "dsk") != NULL;
                    184:         char *p;
                    185: 
                    186:         len = snprintf(pathbuf, sizeof (pathbuf), "%s/", dir);
                    187:         if (len >= sizeof (pathbuf))
                    188:                 return -1;
                    189: 
                    190:         dp = opendir(dir);
                    191:         if (dp == NULL)
                    192:                 return 0;
                    193: 
                    194:         while ((de = readdir(dp)) != NULL) {
                    195:                 if (de->d_name[0] == '.')
                    196:                         continue;
                    197: 
                    198:                 if (strlen(de->d_name) + len >= sizeof (pathbuf))
                    199:                         continue;
                    200: 
                    201:                 if (isdisk) {
                    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')
                    206:                                 continue;
                    207:                 } else {
                    208:                         /* Tape drive represented by the all-digit device */
                    209:                         for (p = de->d_name; *p; p++)
                    210:                                 if (!isdigit((int)(*p)))
                    211:                                         break;
                    212:                         if (*p != '\0')
                    213:                                 continue;
                    214:                 }
                    215:                 strcpy(&pathbuf[len], de->d_name);
                    216:                 if (testfun(pathbuf)) {
                    217:                         if (addpath(pathbuf, res) == -1) {
                    218:                                 closedir(dp);
                    219:                                 return -1;
                    220:                         }
                    221:                 }
                    222:         }
                    223:         closedir(dp);
                    224: 
                    225:         return 0;
                    226: }
                    227: 
                    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) {
                    231:         struct pathlist res;
                    232: 
                    233:         res.nnames = res.maxnames = 0;
                    234:         res.names = NULL;
                    235:         if (strcmp(name, "SCSI") == 0) {
                    236:                 if (grokdir("/dev/rdsk", &res, isscsidev) == -1)
                    237:                         return -1;
                    238:                 if (grokdir("/dev/rmt", &res, isscsidev) == -1)
                    239:                         return -1;
                    240:        } else if (strcmp(name, "ATA") == 0) {
                    241:                 if (grokdir("/dev/rdsk", &res, isatadev) == -1)
                    242:                         return -1;
                    243:        } else {
                    244:                 // non-SCSI and non-ATA case not implemented
                    245:                 *devlist=NULL;
                    246:                 return 0;
                    247:        }
                    248: 
                    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);
                    252: 
                    253:        // pass list back
                    254:        *devlist = res.names;
                    255:        return res.nnames;
                    256: }
                    257: 
                    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);
                    265:   else
                    266:     return -1;
                    267: }
                    268: 
                    269: // Like close().  Acts on handles returned by above function.
                    270: int deviceclose(int fd){
                    271:     return close(fd);
                    272: }
                    273: 
                    274: #if defined(__sparc)
                    275: // swap each 2-byte pairs in a sector
                    276: static void swap_sector(void *p)
                    277: {
                    278:     int i;
                    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;
                    282:         cp += 2;
                    283:     }
                    284: }
                    285: #endif
                    286: 
                    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);
                    290:     return -1;
                    291: }
                    292: 
                    293: int highpoint_command_interface(int fd, smart_command_set command, int select, char *data)
                    294: {
                    295:     ARGUSED(fd); ARGUSED(command); ARGUSED(select); ARGUSED(data);
                    296:     return -1;
                    297: }
                    298: 
                    299: int ata_command_interface(int fd, smart_command_set command, int select, char *data){
                    300: #if defined(__sparc)
                    301:     int err;
                    302:  
                    303:     switch (command){
                    304:     case CHECK_POWER_MODE:
                    305:        /* currently not recognized */
                    306:        return -1;
                    307:     case READ_VALUES:
                    308:        return smart_read_data(fd, data);
                    309:     case READ_THRESHOLDS:
                    310:        return smart_read_thresholds(fd, data);
                    311:     case READ_LOG:
                    312:        return smart_read_log(fd, select, 1, data);
                    313:     case IDENTIFY:
                    314:        err = ata_identify(fd, data);
                    315:        if(err) return err;
                    316:        swap_sector(static_cast<void*>(data));
                    317:        return 0;
                    318:     case PIDENTIFY:
                    319:        err = ata_pidentify(fd, data);
                    320:        if(err) return err;
                    321:        swap_sector(static_cast<void*>(data));
                    322:        return 0;
                    323:     case ENABLE:
                    324:        return smart_enable(fd);
                    325:     case DISABLE:
                    326:        return smart_disable(fd);
                    327:     case STATUS:
                    328:        return smart_status(fd);
                    329:     case AUTO_OFFLINE:
                    330:        return smart_auto_offline(fd, select);
                    331:     case AUTOSAVE:
                    332:        return smart_auto_save(fd, select);
                    333:     case IMMEDIATE_OFFLINE:
                    334:        return smart_immediate_offline(fd, select);
                    335:     case STATUS_CHECK:
                    336:        return smart_status_check(fd);
                    337:     default:
                    338:        pout("Unrecognized command %d in ata_command_interface() of os_solaris.c\n", command);
                    339:        EXIT(1);
                    340:        break;
                    341:     }
                    342: #else /* __sparc */
                    343:     ARGUSED(fd); ARGUSED(command); ARGUSED(select); ARGUSED(data);
                    344: 
                    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... */
                    349:     if (printwarning(0))
                    350:        return -1;
                    351: #endif
                    352:     return -1;
                    353: }
                    354: 
                    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); 
                    359: 
                    360:   if (printwarning(1))
                    361:     return -1;
                    362:   return -1;
                    363: }
                    364: 
                    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); 
                    368: 
                    369:   if (printwarning(1))
                    370:     return -1;
                    371:   return -1;
                    372: }
                    373: 
                    374: #include <errno.h>
                    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>
                    379: 
                    380: // Interface to SCSI devices.  See os_linux.c
                    381: int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
                    382: {
                    383:   struct uscsi_cmd uscsi;
                    384: 
                    385:   if (report > 0) {
                    386:     int k;
                    387:     const unsigned char * ucp = iop->cmnd;
                    388:     const char * np;
                    389: 
                    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]);
                    394:     pout("]\n");
                    395:     if ((report > 1) && 
                    396:         (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
                    397:       int trunc = (iop->dxfer_len > 256) ? 1 : 0;
                    398: 
                    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);
                    402:     }
                    403:   }
                    404:   memset(&uscsi, 0, sizeof (uscsi));
                    405: 
                    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 */
                    410:   else
                    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;
                    416: 
                    417:   switch (iop->dxfer_dir) {
                    418:   case DXFER_NONE:
                    419:   case DXFER_FROM_DEVICE:
                    420:     uscsi.uscsi_flags = USCSI_READ;
                    421:     break;
                    422:   case DXFER_TO_DEVICE:
                    423:     uscsi.uscsi_flags = USCSI_WRITE;
                    424:     break;
                    425:   default:
                    426:     return -EINVAL;
                    427:   }
                    428:   uscsi.uscsi_flags |= (USCSI_ISOLATE | USCSI_RQENABLE);
                    429: 
                    430:   if (ioctl(fd, USCSICMD, &uscsi)) {
                    431:     int err = errno;
                    432: 
                    433:     if (! ((EIO == err) && uscsi.uscsi_status))
                    434:       return -err;
                    435:     /* errno is set to EIO when a non-zero SCSI completion status given */
                    436:   }
                    437: 
                    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;
                    441: 
                    442:   if (report > 0) {
                    443:     int trunc;
                    444:     int len = iop->resp_sense_len;
                    445: 
                    446:     if ((SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) &&
                    447:         iop->sensep && (len > 3)) {
                    448:       if ((iop->sensep[0] & 0x7f) > 0x71)
                    449:         pout("  status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
                    450:              iop->scsi_status, iop->sensep[1] & 0xf,
                    451:              iop->sensep[2], iop->sensep[3]);
                    452:       else
                    453:         pout("  status=%x: sense_key=%x asc=%x ascq=%x\n",
                    454:              iop->scsi_status, iop->sensep[2] & 0xf,
                    455:              iop->sensep[12], iop->sensep[13]);
                    456:       if (report > 1) {
                    457:           pout("  >>> Sense buffer, len=%d:\n", len);
                    458:           dStrHex((const char *)iop->sensep, ((len > 252) ? 252 : len) , 1);
                    459:       }
                    460:     } else if (iop->scsi_status)
                    461:       pout("  status=%x\n", iop->scsi_status);
                    462:     if (iop->resid)
                    463:       pout("  dxfer_len=%d, resid=%d\n", iop->dxfer_len, iop->resid);
                    464:     if (report > 1) {
                    465:       len = iop->dxfer_len - iop->resid;
                    466:       if (len > 0) {
                    467:         trunc = (len > 256) ? 1 : 0;
                    468:         pout("  Incoming data, len=%d%s:\n", len,
                    469:              (trunc ? " [only first 256 bytes shown]" : ""));
                    470:         dStrHex((char *)iop->dxferp, (trunc ? 256 : len) , 1);
                    471:       }
                    472:     }
                    473:   }
                    474:   return 0;
                    475: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>