]>
Commit | Line | Data |
---|---|---|
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 |