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