]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - cciss.cpp
import smartmontools 7.0
[mirror_smartmontools-debian.git] / cciss.cpp
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
11 #include <stdio.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #include <errno.h>
15
16 #include "config.h"
17
18 #if defined(linux) || defined(__linux__)
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>
28 # ifndef be32toh
29 # define be32toh __be32_to_cpu
30 # endif
31 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
32 # include <sys/endian.h>
33 # include CISS_LOCATION
34 # define _HAVE_CCISS
35 #endif
36
37 #ifdef _HAVE_CCISS
38 #include "cciss.h"
39 #include "scsicmds.h"
40 #include "utility.h"
41
42 const char * cciss_cpp_cvsid = "$Id: cciss.cpp 4858 2018-12-16 17:59:59Z chrfranke $"
43 CCISS_H_CVSID;
44
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;
77 int len = 0; // used later in the code.
78
79 int status = cciss_getlun(device, target, phylun, report);
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]" : ""));
102 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
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);
120 dStrHex((const uint8_t *)pBuf, len , 1);
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 {
184 fprintf(stderr, "CCISS ioctl error %d (fd %d CDBLen %u buf_size %u)\n",
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;
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 }
226 pout("===== [%s] DATA END (%u Bytes) =====\n\n", "LUN DATA", (unsigned)sizeof(_ReportLUNdata_struct));
227 }
228
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 }
235
236 free(luns);
237 return 1;
238 }
239 #endif