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