File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / smartmontools / os_solaris.cpp
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 07:54:03 2013 UTC (10 years, 8 months ago) by misho
Branches: smartmontools, elwix, MAIN
CVS tags: v6_2, HEAD
v 6.2

    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 Software Foundation,
   16:  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.1.1.3 2013/10/14 07:54:03 misho Exp $";
   43: 
   44: const char *os_XXXX_c_cvsid="$Id: os_solaris.cpp,v 1.1.1.3 2013/10/14 07:54:03 misho 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 ata_command_interface(int fd, smart_command_set command, int select, char *data){
  289: #if defined(__sparc)
  290:     int err;
  291:  
  292:     switch (command){
  293:     case CHECK_POWER_MODE:
  294: 	/* currently not recognized */
  295: 	return -1;
  296:     case READ_VALUES:
  297: 	return smart_read_data(fd, data);
  298:     case READ_THRESHOLDS:
  299: 	return smart_read_thresholds(fd, data);
  300:     case READ_LOG:
  301: 	return smart_read_log(fd, select, 1, data);
  302:     case IDENTIFY:
  303: 	err = ata_identify(fd, data);
  304: 	if(err) return err;
  305: 	swap_sector(static_cast<void*>(data));
  306: 	return 0;
  307:     case PIDENTIFY:
  308: 	err = ata_pidentify(fd, data);
  309: 	if(err) return err;
  310: 	swap_sector(static_cast<void*>(data));
  311: 	return 0;
  312:     case ENABLE:
  313: 	return smart_enable(fd);
  314:     case DISABLE:
  315: 	return smart_disable(fd);
  316:     case STATUS:
  317: 	return smart_status(fd);
  318:     case AUTO_OFFLINE:
  319: 	return smart_auto_offline(fd, select);
  320:     case AUTOSAVE:
  321: 	return smart_auto_save(fd, select);
  322:     case IMMEDIATE_OFFLINE:
  323: 	return smart_immediate_offline(fd, select);
  324:     case STATUS_CHECK:
  325: 	return smart_status_check(fd);
  326:     default:
  327: 	pout("Unrecognized command %d in ata_command_interface() of os_solaris.c\n", command);
  328: 	EXIT(1);
  329: 	break;
  330:     }
  331: #else /* __sparc */
  332:     ARGUSED(fd); ARGUSED(command); ARGUSED(select); ARGUSED(data);
  333: 
  334:     /* Above smart_* routines uses undocumented ioctls of "dada"
  335:      * driver, which is specific to SPARC Solaris.  See
  336:      * os_solaris_ata.s for further details. x86 Solaris seems not to
  337:      * provide similar or alternative interface... */
  338:     if (printwarning(0))
  339: 	return -1;
  340: #endif
  341:     return -1;
  342: }
  343: 
  344: #include <errno.h>
  345: #include <sys/scsi/generic/commands.h>
  346: #include <sys/scsi/generic/status.h>
  347: #include <sys/scsi/impl/types.h>
  348: #include <sys/scsi/impl/uscsi.h>
  349: 
  350: // Interface to SCSI devices.  See os_linux.c
  351: int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
  352: {
  353:   struct uscsi_cmd uscsi;
  354: 
  355:   if (report > 0) {
  356:     int k;
  357:     const unsigned char * ucp = iop->cmnd;
  358:     const char * np;
  359: 
  360:     np = scsi_get_opcode_name(ucp[0]);
  361:     pout(" [%s: ", np ? np : "<unknown opcode>");
  362:     for (k = 0; k < (int)iop->cmnd_len; ++k)
  363:       pout("%02x ", ucp[k]);
  364:     pout("]\n");
  365:     if ((report > 1) && 
  366:         (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
  367:       int trunc = (iop->dxfer_len > 256) ? 1 : 0;
  368: 
  369:       pout("  Outgoing data, len=%d%s:\n", (int)iop->dxfer_len,
  370:            (trunc ? " [only first 256 bytes shown]" : ""));
  371:       dStrHex((char *)iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
  372:     }
  373:   }
  374:   memset(&uscsi, 0, sizeof (uscsi));
  375: 
  376:   uscsi.uscsi_cdb = reinterpret_cast<char*>(iop->cmnd);
  377:   uscsi.uscsi_cdblen = iop->cmnd_len;
  378:   if (iop->timeout == 0)
  379:     uscsi.uscsi_timeout = 60; /* 60 seconds */
  380:   else
  381:     uscsi.uscsi_timeout = iop->timeout;
  382:   uscsi.uscsi_bufaddr = reinterpret_cast<char*>(iop->dxferp);
  383:   uscsi.uscsi_buflen = iop->dxfer_len;
  384:   uscsi.uscsi_rqbuf = reinterpret_cast<char*>(iop->sensep);
  385:   uscsi.uscsi_rqlen = iop->max_sense_len;
  386: 
  387:   switch (iop->dxfer_dir) {
  388:   case DXFER_NONE:
  389:   case DXFER_FROM_DEVICE:
  390:     uscsi.uscsi_flags = USCSI_READ;
  391:     break;
  392:   case DXFER_TO_DEVICE:
  393:     uscsi.uscsi_flags = USCSI_WRITE;
  394:     break;
  395:   default:
  396:     return -EINVAL;
  397:   }
  398:   uscsi.uscsi_flags |= (USCSI_ISOLATE | USCSI_RQENABLE);
  399: 
  400:   if (ioctl(fd, USCSICMD, &uscsi)) {
  401:     int err = errno;
  402: 
  403:     if (! ((EIO == err) && uscsi.uscsi_status))
  404:       return -err;
  405:     /* errno is set to EIO when a non-zero SCSI completion status given */
  406:   }
  407: 
  408:   iop->scsi_status = uscsi.uscsi_status;
  409:   iop->resid = uscsi.uscsi_resid;
  410:   iop->resp_sense_len = iop->max_sense_len - uscsi.uscsi_rqresid;
  411: 
  412:   if (report > 0) {
  413:     int trunc;
  414:     int len = iop->resp_sense_len;
  415: 
  416:     if ((SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) &&
  417:         iop->sensep && (len > 3)) {
  418:       if ((iop->sensep[0] & 0x7f) > 0x71)
  419:         pout("  status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
  420:              iop->scsi_status, iop->sensep[1] & 0xf,
  421:              iop->sensep[2], iop->sensep[3]);
  422:       else
  423:         pout("  status=%x: sense_key=%x asc=%x ascq=%x\n",
  424:              iop->scsi_status, iop->sensep[2] & 0xf,
  425:              iop->sensep[12], iop->sensep[13]);
  426:       if (report > 1) {
  427:           pout("  >>> Sense buffer, len=%d:\n", len);
  428:           dStrHex((const char *)iop->sensep, ((len > 252) ? 252 : len) , 1);
  429:       }
  430:     } else if (iop->scsi_status)
  431:       pout("  status=%x\n", iop->scsi_status);
  432:     if (iop->resid)
  433:       pout("  dxfer_len=%d, resid=%d\n", iop->dxfer_len, iop->resid);
  434:     if (report > 1) {
  435:       len = iop->dxfer_len - iop->resid;
  436:       if (len > 0) {
  437:         trunc = (len > 256) ? 1 : 0;
  438:         pout("  Incoming data, len=%d%s:\n", len,
  439:              (trunc ? " [only first 256 bytes shown]" : ""));
  440:         dStrHex((char *)iop->dxferp, (trunc ? 256 : len) , 1);
  441:       }
  442:     }
  443:   }
  444:   return 0;
  445: }

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