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