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