smartmontools SVN Rev 3317
Utility to control and monitor storage systems with "S.M.A.R.T."
cciss.cpp
Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <string.h>
00003 #include <sys/types.h>
00004 #include <errno.h>
00005 
00006 #include "config.h"
00007 
00008 #if defined(linux)
00009 #  include <sys/ioctl.h>
00010 #  ifdef HAVE_LINUX_COMPILER_H
00011 #    include <linux/compiler.h>
00012 #  endif
00013 #  if defined(HAVE_LINUX_CCISS_IOCTL_H)
00014 #    include <linux/cciss_ioctl.h>
00015 #    define _HAVE_CCISS
00016 #  endif
00017 #  include <asm/byteorder.h>
00018 #  ifndef be32toh
00019 #    define be32toh __be32_to_cpu
00020 #  endif
00021 #elif defined(__FreeBSD__)
00022 #  include <sys/endian.h>
00023 #  include CISS_LOCATION
00024 #  define _HAVE_CCISS
00025 #elif defined(__FreeBSD_kernel__)
00026 #  include <endian.h>
00027 #  ifdef __GLIBC__
00028 #  include <bsd/sys/cdefs.h>
00029 #  include <stdint.h>
00030 #  endif
00031 #  include CISS_LOCATION
00032 #  define _HAVE_CCISS
00033 #endif
00034 
00035 #ifdef _HAVE_CCISS
00036 #include "cciss.h"
00037 #include "int64.h"
00038 #include "scsicmds.h"
00039 #include "utility.h"
00040 
00041 const char * cciss_cpp_cvsid = "$Id: cciss.cpp 3578 2012-07-20 17:26:32Z chrfranke $"
00042   CCISS_H_CVSID;
00043 
00044 typedef struct _ReportLUNdata_struct
00045 {
00046   uint32_t LUNListLength;       /* always big-endian */
00047   uint32_t reserved;
00048   uint8_t LUN[CISS_MAX_LUN][8];
00049 } ReportLunData_struct;
00050 
00051 /* Structure/defines of Report Physical LUNS of drive */
00052 #ifndef CISS_MAX_LUN
00053 #define CISS_MAX_LUN        16
00054 #endif
00055 #define CISS_MAX_PHYS_LUN   1024
00056 #define CISS_REPORT_PHYS    0xc3
00057 
00058 #define LSCSI_DRIVER_SENSE  0x8         /* alternate CHECK CONDITION indication */
00059 #define SEND_IOCTL_RESP_SENSE_LEN 16    /* ioctl limitation */
00060 
00061 static int cciss_getlun(int device, int target, unsigned char *physlun, int report);
00062 static int cciss_sendpassthru(unsigned int cmdtype, unsigned char *CDB,
00063                         unsigned int CDBlen, char *buff,
00064                         unsigned int size, unsigned int LunID,
00065                         unsigned char *scsi3addr, int fd);
00066 
00067 /* 
00068    This is an interface that uses the cciss passthrough to talk to the SMART controller on
00069    the HP system. The cciss driver provides a way to send SCSI cmds through the CCISS passthrough.
00070 */
00071 int cciss_io_interface(int device, int target, struct scsi_cmnd_io * iop, int report)
00072 {
00073      unsigned char pBuf[512] = {0};
00074      unsigned char phylun[8] = {0};
00075      int iBufLen = 512;
00076      int status = -1;
00077      int len = 0; // used later in the code.
00078  
00079      status = cciss_getlun(device, target, phylun, report);
00080      if (report > 0)
00081          printf("  cciss_getlun(%d, %d) = 0x%x; scsi3addr: %02x %02x %02x %02x %02x %02x %02x %02x\n", 
00082              device, target, status, 
00083              phylun[0], phylun[1], phylun[2], phylun[3], phylun[4], phylun[5], phylun[6], phylun[7]);
00084      if (status) {
00085          return -ENXIO;      /* give up, assume no device there */
00086      }
00087 
00088      status = cciss_sendpassthru( 2, iop->cmnd, iop->cmnd_len, (char*) pBuf, iBufLen, 1, phylun, device);
00089  
00090      if (0 == status)
00091      {
00092          if (report > 0)
00093              printf("  status=0\n");
00094          if (DXFER_FROM_DEVICE == iop->dxfer_dir)
00095          {
00096              memcpy(iop->dxferp, pBuf, iop->dxfer_len);
00097              if (report > 1)
00098              {
00099                  int trunc = (iop->dxfer_len > 256) ? 1 : 0;
00100                  printf("  Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
00101                       (trunc ? " [only first 256 bytes shown]" : ""));
00102                  dStrHex((const char*)iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
00103              }
00104          }
00105          return 0;
00106      }
00107      iop->scsi_status = status & 0x7e; /* bits 0 and 7 used to be for vendors */
00108      if (LSCSI_DRIVER_SENSE == ((status >> 24) & 0xf))
00109          iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;
00110      len = (SEND_IOCTL_RESP_SENSE_LEN < iop->max_sense_len) ?
00111                 SEND_IOCTL_RESP_SENSE_LEN : iop->max_sense_len;
00112      if ((SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) &&
00113          iop->sensep && (len > 0))
00114      {
00115          memcpy(iop->sensep, pBuf, len);
00116          iop->resp_sense_len = iBufLen;
00117          if (report > 1)
00118          {
00119              printf("  >>> Sense buffer, len=%d:\n", (int)len);
00120              dStrHex((const char *)pBuf, len , 1);
00121          }
00122      }
00123      if (report)
00124      {
00125          if (SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) {
00126              printf("  status=%x: sense_key=%x asc=%x ascq=%x\n", status & 0xff,
00127                   pBuf[2] & 0xf, pBuf[12], pBuf[13]);
00128          }
00129          else
00130              printf("  status=0x%x\n", status);
00131      }
00132      if (iop->scsi_status > 0)
00133          return 0;
00134      else
00135      {
00136          if (report > 0)
00137              printf("  ioctl status=0x%x but scsi status=0, fail with ENXIO\n", status);
00138          return -ENXIO;      /* give up, assume no device there */
00139      }
00140 } 
00141 
00142 static int cciss_sendpassthru(unsigned int cmdtype, unsigned char *CDB,
00143                         unsigned int CDBlen, char *buff,
00144                         unsigned int size, unsigned int LunID,
00145                         unsigned char *scsi3addr, int fd)
00146 {
00147     int err ;
00148     IOCTL_Command_struct iocommand;
00149 
00150     memset(&iocommand, 0, sizeof(iocommand));
00151 
00152     if (cmdtype == 0) 
00153     {
00154         // To controller; nothing to do
00155     }
00156     else if (cmdtype == 1) 
00157     {
00158         iocommand.LUN_info.LogDev.VolId = LunID;
00159         iocommand.LUN_info.LogDev.Mode = 1;
00160     }
00161     else if (cmdtype == 2) 
00162     {
00163         memcpy(&iocommand.LUN_info.LunAddrBytes,scsi3addr,8);
00164         iocommand.LUN_info.LogDev.Mode = 0;
00165     }
00166     else 
00167     {
00168         fprintf(stderr, "cciss_sendpassthru: bad cmdtype\n");
00169         return 1;
00170     }
00171 
00172     memcpy(&iocommand.Request.CDB[0], CDB, CDBlen);
00173     iocommand.Request.CDBLen = CDBlen;
00174     iocommand.Request.Type.Type = TYPE_CMD;
00175     iocommand.Request.Type.Attribute = ATTR_SIMPLE;
00176     iocommand.Request.Type.Direction = XFER_READ;
00177     iocommand.Request.Timeout = 0;
00178 
00179     iocommand.buf_size = size;
00180     iocommand.buf = (unsigned char *)buff;
00181 
00182     if ((err = ioctl(fd, CCISS_PASSTHRU, &iocommand))) 
00183     {
00184         fprintf(stderr, "CCISS ioctl error %d (fd %d CDBLen %d buf_size %d)\n",
00185             fd, err, CDBlen, size);
00186     }
00187     return err;
00188 }
00189 
00190 static int cciss_getlun(int device, int target, unsigned char *physlun, int report)
00191 {
00192     unsigned char CDB[16]= {0};
00193     ReportLunData_struct *luns;
00194     int reportlunsize = sizeof(*luns) + CISS_MAX_PHYS_LUN * 8;
00195     int ret;
00196 
00197     luns = (ReportLunData_struct *)malloc(reportlunsize);
00198 
00199     memset(luns, 0, reportlunsize);
00200 
00201     /* Get Physical LUN Info (for physical device) */
00202     CDB[0] = CISS_REPORT_PHYS;
00203     CDB[6] = (reportlunsize >> 24) & 0xFF;  /* MSB */
00204     CDB[7] = (reportlunsize >> 16) & 0xFF;
00205     CDB[8] = (reportlunsize >> 8) & 0xFF;
00206     CDB[9] = reportlunsize & 0xFF;
00207 
00208     if ((ret = cciss_sendpassthru(0, CDB, 12, (char *)luns, reportlunsize, 0, NULL, device)))
00209     {
00210         free(luns);
00211         return ret;
00212     }
00213 
00214     if (report > 1)
00215     {
00216       unsigned int i,j;
00217       unsigned char *stuff = (unsigned char *)luns;
00218 
00219       pout("\n===== [%s] DATA START (BASE-16) =====\n", "LUN DATA");
00220       for (i=0; i<(sizeof(_ReportLUNdata_struct)+15)/16; i++){
00221         pout("%03d-%03d: ", 16*i, 16*(i+1)-1);
00222         for (j=0; j<15; j++)
00223           pout("%02x ",*stuff++);
00224         pout("%02x\n",*stuff++);
00225       }
00226       pout("===== [%s] DATA END (%u Bytes) =====\n\n", "LUN DATA", (unsigned)sizeof(_ReportLUNdata_struct));
00227     }
00228 
00229     if (target >= 0 && target < (int) be32toh(luns->LUNListLength) / 8)
00230     {
00231         memcpy(physlun, luns->LUN[target], 8);
00232         free(luns);
00233         return 0;
00234     }
00235 
00236     free(luns);
00237     return 1;
00238 }
00239 #endif