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