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