smartmontools  SVN Rev 4071
Utility to control and monitor storage systems with "S.M.A.R.T."
cciss.cpp
Go to the documentation of this file.
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) || 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 3945 2014-07-13 15:29:05Z chrfranke $"
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))
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  {
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
#define TYPE_CMD
u32 size
Definition: megaraid.h:79
#define SCSI_STATUS_CHECK_CONDITION
Definition: scsicmds.h:260
UINT8 * sensep
Definition: scsicmds.h:124
#define DXFER_FROM_DEVICE
Definition: scsicmds.h:113
size_t resp_sense_len
Definition: scsicmds.h:128
UINT8 * dxferp
Definition: scsicmds.h:122
UINT8 * cmnd
Definition: scsicmds.h:118
void dStrHex(const char *str, int len, int no_ascii)
Definition: scsicmds.cpp:91
void pout(const char *fmt,...)
Definition: smartctl.cpp:1091
#define ATTR_SIMPLE
size_t max_sense_len
Definition: scsicmds.h:126
int dxfer_dir
Definition: scsicmds.h:120
#define SEND_IOCTL_RESP_SENSE_LEN
Definition: os_linux.cpp:499
#define CISS_MAX_LUN
#define CCISS_H_CVSID
Definition: cciss.h:4
size_t cmnd_len
Definition: scsicmds.h:119
#define LSCSI_DRIVER_SENSE
Definition: os_linux.cpp:502
#define XFER_READ
UINT8 scsi_status
Definition: scsicmds.h:129
#define CCISS_PASSTHRU
size_t dxfer_len
Definition: scsicmds.h:123
int cciss_io_interface(int device, int target, struct scsi_cmnd_io *iop, int report)