File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / smartmontools / cciss.cpp
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:17:35 2013 UTC (10 years, 10 months ago) by misho
Branches: smartmontools, elwix, MAIN
CVS tags: v6_2, v6_1p0, v6_1, HEAD
6.1

    1: #include <stdio.h>
    2: #include <string.h>
    3: #include <sys/types.h>
    4: #include <errno.h>
    5: 
    6: #include "config.h"
    7: 
    8: #if defined(linux)
    9: #  include <sys/ioctl.h>
   10: #  ifdef HAVE_LINUX_COMPILER_H
   11: #    include <linux/compiler.h>
   12: #  endif
   13: #  if defined(HAVE_LINUX_CCISS_IOCTL_H)
   14: #    include <linux/cciss_ioctl.h>
   15: #    define _HAVE_CCISS
   16: #  endif
   17: #  include <asm/byteorder.h>
   18: #  ifndef be32toh
   19: #    define be32toh __be32_to_cpu
   20: #  endif
   21: #elif defined(__FreeBSD__)
   22: #  include <sys/endian.h>
   23: #  include CISS_LOCATION
   24: #  define _HAVE_CCISS
   25: #elif defined(__FreeBSD_kernel__)
   26: #  include <endian.h>
   27: #  ifdef __GLIBC__
   28: #  include <bsd/sys/cdefs.h>
   29: #  include <stdint.h>
   30: #  endif
   31: #  include CISS_LOCATION
   32: #  define _HAVE_CCISS
   33: #endif
   34: 
   35: #ifdef _HAVE_CCISS
   36: #include "cciss.h"
   37: #include "int64.h"
   38: #include "scsicmds.h"
   39: #include "utility.h"
   40: 
   41: const char * cciss_cpp_cvsid = "$Id: cciss.cpp,v 1.1.1.2 2013/07/22 01:17:35 misho Exp $"
   42:   CCISS_H_CVSID;
   43: 
   44: typedef struct _ReportLUNdata_struct
   45: {
   46:   uint32_t LUNListLength;	/* always big-endian */
   47:   uint32_t reserved;
   48:   uint8_t LUN[CISS_MAX_LUN][8];
   49: } ReportLunData_struct;
   50: 
   51: /* Structure/defines of Report Physical LUNS of drive */
   52: #ifndef CISS_MAX_LUN
   53: #define CISS_MAX_LUN        16
   54: #endif
   55: #define CISS_MAX_PHYS_LUN   1024
   56: #define CISS_REPORT_PHYS    0xc3
   57: 
   58: #define LSCSI_DRIVER_SENSE  0x8		/* alternate CHECK CONDITION indication */
   59: #define SEND_IOCTL_RESP_SENSE_LEN 16    /* ioctl limitation */
   60: 
   61: static int cciss_getlun(int device, int target, unsigned char *physlun, int report);
   62: static int cciss_sendpassthru(unsigned int cmdtype, unsigned char *CDB,
   63:     			unsigned int CDBlen, char *buff,
   64:     			unsigned int size, unsigned int LunID,
   65:     			unsigned char *scsi3addr, int fd);
   66: 
   67: /* 
   68:    This is an interface that uses the cciss passthrough to talk to the SMART controller on
   69:    the HP system. The cciss driver provides a way to send SCSI cmds through the CCISS passthrough.
   70: */
   71: int cciss_io_interface(int device, int target, struct scsi_cmnd_io * iop, int report)
   72: {
   73:      unsigned char pBuf[512] = {0};
   74:      unsigned char phylun[8] = {0};
   75:      int iBufLen = 512;
   76:      int status = -1;
   77:      int len = 0; // used later in the code.
   78:  
   79:      status = cciss_getlun(device, target, phylun, report);
   80:      if (report > 0)
   81:          printf("  cciss_getlun(%d, %d) = 0x%x; scsi3addr: %02x %02x %02x %02x %02x %02x %02x %02x\n", 
   82: 	     device, target, status, 
   83: 	     phylun[0], phylun[1], phylun[2], phylun[3], phylun[4], phylun[5], phylun[6], phylun[7]);
   84:      if (status) {
   85:          return -ENXIO;      /* give up, assume no device there */
   86:      }
   87: 
   88:      status = cciss_sendpassthru( 2, iop->cmnd, iop->cmnd_len, (char*) pBuf, iBufLen, 1, phylun, device);
   89:  
   90:      if (0 == status)
   91:      {
   92:          if (report > 0)
   93:              printf("  status=0\n");
   94:          if (DXFER_FROM_DEVICE == iop->dxfer_dir)
   95:          {
   96:              memcpy(iop->dxferp, pBuf, iop->dxfer_len);
   97:              if (report > 1)
   98:              {
   99:                  int trunc = (iop->dxfer_len > 256) ? 1 : 0;
  100:                  printf("  Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
  101:                       (trunc ? " [only first 256 bytes shown]" : ""));
  102:                  dStrHex((const char*)iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
  103:              }
  104:          }
  105:          return 0;
  106:      }
  107:      iop->scsi_status = status & 0x7e; /* bits 0 and 7 used to be for vendors */
  108:      if (LSCSI_DRIVER_SENSE == ((status >> 24) & 0xf))
  109:          iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;
  110:      len = (SEND_IOCTL_RESP_SENSE_LEN < iop->max_sense_len) ?
  111:                 SEND_IOCTL_RESP_SENSE_LEN : iop->max_sense_len;
  112:      if ((SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) &&
  113:          iop->sensep && (len > 0))
  114:      {
  115:          memcpy(iop->sensep, pBuf, len);
  116:          iop->resp_sense_len = iBufLen;
  117:          if (report > 1)
  118:          {
  119:              printf("  >>> Sense buffer, len=%d:\n", (int)len);
  120:              dStrHex((const char *)pBuf, len , 1);
  121:          }
  122:      }
  123:      if (report)
  124:      {
  125:          if (SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) {
  126:              printf("  status=%x: sense_key=%x asc=%x ascq=%x\n", status & 0xff,
  127:                   pBuf[2] & 0xf, pBuf[12], pBuf[13]);
  128:          }
  129:          else
  130:              printf("  status=0x%x\n", status);
  131:      }
  132:      if (iop->scsi_status > 0)
  133:          return 0;
  134:      else
  135:      {
  136:          if (report > 0)
  137:              printf("  ioctl status=0x%x but scsi status=0, fail with ENXIO\n", status);
  138:          return -ENXIO;      /* give up, assume no device there */
  139:      }
  140: } 
  141: 
  142: static int cciss_sendpassthru(unsigned int cmdtype, unsigned char *CDB,
  143:     			unsigned int CDBlen, char *buff,
  144:     			unsigned int size, unsigned int LunID,
  145:     			unsigned char *scsi3addr, int fd)
  146: {
  147:     int err ;
  148:     IOCTL_Command_struct iocommand;
  149: 
  150:     memset(&iocommand, 0, sizeof(iocommand));
  151: 
  152:     if (cmdtype == 0) 
  153:     {
  154:         // To controller; nothing to do
  155:     }
  156:     else if (cmdtype == 1) 
  157:     {
  158:         iocommand.LUN_info.LogDev.VolId = LunID;
  159:         iocommand.LUN_info.LogDev.Mode = 1;
  160:     }
  161:     else if (cmdtype == 2) 
  162:     {
  163:         memcpy(&iocommand.LUN_info.LunAddrBytes,scsi3addr,8);
  164:         iocommand.LUN_info.LogDev.Mode = 0;
  165:     }
  166:     else 
  167:     {
  168:         fprintf(stderr, "cciss_sendpassthru: bad cmdtype\n");
  169:         return 1;
  170:     }
  171: 
  172:     memcpy(&iocommand.Request.CDB[0], CDB, CDBlen);
  173:     iocommand.Request.CDBLen = CDBlen;
  174:     iocommand.Request.Type.Type = TYPE_CMD;
  175:     iocommand.Request.Type.Attribute = ATTR_SIMPLE;
  176:     iocommand.Request.Type.Direction = XFER_READ;
  177:     iocommand.Request.Timeout = 0;
  178: 
  179:     iocommand.buf_size = size;
  180:     iocommand.buf = (unsigned char *)buff;
  181: 
  182:     if ((err = ioctl(fd, CCISS_PASSTHRU, &iocommand))) 
  183:     {
  184:         fprintf(stderr, "CCISS ioctl error %d (fd %d CDBLen %d buf_size %d)\n",
  185: 	    fd, err, CDBlen, size);
  186:     }
  187:     return err;
  188: }
  189: 
  190: static int cciss_getlun(int device, int target, unsigned char *physlun, int report)
  191: {
  192:     unsigned char CDB[16]= {0};
  193:     ReportLunData_struct *luns;
  194:     int reportlunsize = sizeof(*luns) + CISS_MAX_PHYS_LUN * 8;
  195:     int ret;
  196: 
  197:     luns = (ReportLunData_struct *)malloc(reportlunsize);
  198: 
  199:     memset(luns, 0, reportlunsize);
  200: 
  201:     /* Get Physical LUN Info (for physical device) */
  202:     CDB[0] = CISS_REPORT_PHYS;
  203:     CDB[6] = (reportlunsize >> 24) & 0xFF;  /* MSB */
  204:     CDB[7] = (reportlunsize >> 16) & 0xFF;
  205:     CDB[8] = (reportlunsize >> 8) & 0xFF;
  206:     CDB[9] = reportlunsize & 0xFF;
  207: 
  208:     if ((ret = cciss_sendpassthru(0, CDB, 12, (char *)luns, reportlunsize, 0, NULL, device)))
  209:     {
  210:         free(luns);
  211:         return ret;
  212:     }
  213: 
  214:     if (report > 1)
  215:     {
  216:       unsigned int i,j;
  217:       unsigned char *stuff = (unsigned char *)luns;
  218: 
  219:       pout("\n===== [%s] DATA START (BASE-16) =====\n", "LUN DATA");
  220:       for (i=0; i<(sizeof(_ReportLUNdata_struct)+15)/16; i++){
  221: 	pout("%03d-%03d: ", 16*i, 16*(i+1)-1);
  222: 	for (j=0; j<15; j++)
  223: 	  pout("%02x ",*stuff++);
  224: 	pout("%02x\n",*stuff++);
  225:       }
  226:       pout("===== [%s] DATA END (%u Bytes) =====\n\n", "LUN DATA", (unsigned)sizeof(_ReportLUNdata_struct));
  227:     }
  228: 
  229:     if (target >= 0 && target < (int) be32toh(luns->LUNListLength) / 8)
  230:     {
  231: 	memcpy(physlun, luns->LUN[target], 8);
  232: 	free(luns);
  233: 	return 0;
  234:     }
  235: 
  236:     free(luns);
  237:     return 1;
  238: }
  239: #endif 

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