smartmontools SVN Rev 5611
Utility to control and monitor storage systems with "S.M.A.R.T."
cciss.cpp
Go to the documentation of this file.
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
42const char * cciss_cpp_cvsid = "$Id: cciss.cpp 4977 2019-11-22 19:57:04Z chrfranke $"
44
45typedef 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
62static int cciss_getlun(int device, int target, unsigned char *physlun, int report);
63static 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*/
72int cciss_io_interface(int device, int target, struct scsi_cmnd_io * iop, int report)
73{
74 switch (iop->dxfer_dir) {
75 case DXFER_NONE: case DXFER_FROM_DEVICE: break;
76 default: return -ENOTSUP; // TODO: Support DXFER_TO_DEVICE
77 }
78
79 unsigned char phylun[8] = {0};
80
81 int status = cciss_getlun(device, target, phylun, report);
82 if (report > 0)
83 pout(" cciss_getlun(%d, %d) = 0x%x; scsi3addr: %02x %02x %02x %02x %02x %02x %02x %02x\n",
84 device, target, status,
85 phylun[0], phylun[1], phylun[2], phylun[3], phylun[4], phylun[5], phylun[6], phylun[7]);
86 if (status) {
87 return -ENXIO; /* give up, assume no device there */
88 }
89
90 unsigned char sensebuf[SEND_IOCTL_RESP_SENSE_LEN];
91 unsigned char * pBuf = (iop->dxferp ? iop->dxferp : sensebuf);
92 unsigned iBufLen = (iop->dxferp ? iop->dxfer_len : sizeof(sensebuf));
93
94 status = cciss_sendpassthru( 2, iop->cmnd, iop->cmnd_len, (char*) pBuf, iBufLen, 1, phylun, device);
95
96 if (0 == status)
97 {
98 if (report > 0)
99 pout(" status=0\n");
100 if (DXFER_FROM_DEVICE == iop->dxfer_dir)
101 {
102 if (report > 1)
103 {
104 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
105 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
106 (trunc ? " [only first 256 bytes shown]" : ""));
107 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
108 }
109 }
110 return 0;
111 }
112 iop->scsi_status = status & 0x7e; /* bits 0 and 7 used to be for vendors */
113 if (LSCSI_DRIVER_SENSE == ((status >> 24) & 0xf))
115 unsigned len = (SEND_IOCTL_RESP_SENSE_LEN < iop->max_sense_len) ?
117 if (len > iBufLen)
118 len = iBufLen;
120 iop->sensep && (len > 0))
121 {
122 memcpy(iop->sensep, pBuf, len);
123 iop->resp_sense_len = len;
124 if (report > 1)
125 {
126 pout(" >>> Sense buffer, len=%d:\n", (int)len);
127 dStrHex((const uint8_t *)pBuf, len , 1);
128 }
129 }
130 if (report)
131 {
133 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n", status & 0xff,
134 pBuf[2] & 0xf, pBuf[12], pBuf[13]);
135 }
136 else
137 pout(" status=0x%x\n", status);
138 }
139 if (iop->scsi_status > 0)
140 return 0;
141 else
142 {
143 if (report > 0)
144 pout(" ioctl status=0x%x but scsi status=0, fail with ENXIO\n", status);
145 return -ENXIO; /* give up, assume no device there */
146 }
147}
148
149static int cciss_sendpassthru(unsigned int cmdtype, unsigned char *CDB,
150 unsigned int CDBlen, char *buff,
151 unsigned int size, unsigned int LunID,
152 unsigned char *scsi3addr, int fd)
153{
154 int err ;
155 IOCTL_Command_struct iocommand;
156
157 memset(&iocommand, 0, sizeof(iocommand));
158
159 if (cmdtype == 0)
160 {
161 // To controller; nothing to do
162 }
163 else if (cmdtype == 1)
164 {
165 iocommand.LUN_info.LogDev.VolId = LunID;
166 iocommand.LUN_info.LogDev.Mode = 1;
167 }
168 else if (cmdtype == 2)
169 {
170 memcpy(&iocommand.LUN_info.LunAddrBytes,scsi3addr,8);
171 iocommand.LUN_info.LogDev.Mode = 0;
172 }
173 else
174 {
175 pout("cciss_sendpassthru: bad cmdtype\n");
176 return 1;
177 }
178
179 memcpy(&iocommand.Request.CDB[0], CDB, CDBlen);
180 iocommand.Request.CDBLen = CDBlen;
181 iocommand.Request.Type.Type = TYPE_CMD;
182 iocommand.Request.Type.Attribute = ATTR_SIMPLE;
183 iocommand.Request.Type.Direction = XFER_READ; // TODO: OK for DXFER_NONE ?
184 iocommand.Request.Timeout = 0;
185
186 iocommand.buf_size = size;
187 iocommand.buf = (unsigned char *)buff;
188
189 if ((err = ioctl(fd, CCISS_PASSTHRU, &iocommand)))
190 {
191 pout("CCISS ioctl error %d (fd %d CDBLen %u buf_size %u)\n",
192 fd, err, CDBlen, size);
193 }
194 return err;
195}
196
197static int cciss_getlun(int device, int target, unsigned char *physlun, int report)
198{
199 unsigned char CDB[16]= {0};
200 ReportLunData_struct *luns;
201 int reportlunsize = sizeof(*luns) + CISS_MAX_PHYS_LUN * 8;
202 int ret;
203
204 luns = (ReportLunData_struct *)malloc(reportlunsize);
205
206 memset(luns, 0, reportlunsize);
207
208 /* Get Physical LUN Info (for physical device) */
209 CDB[0] = CISS_REPORT_PHYS;
210 CDB[6] = (reportlunsize >> 24) & 0xFF; /* MSB */
211 CDB[7] = (reportlunsize >> 16) & 0xFF;
212 CDB[8] = (reportlunsize >> 8) & 0xFF;
213 CDB[9] = reportlunsize & 0xFF;
214
215 if ((ret = cciss_sendpassthru(0, CDB, 12, (char *)luns, reportlunsize, 0, NULL, device)))
216 {
217 free(luns);
218 return ret;
219 }
220
221 if (report > 1)
222 {
223 unsigned int i,j;
224 unsigned char *stuff = (unsigned char *)luns;
225
226 pout("\n===== [%s] DATA START (BASE-16) =====\n", "LUN DATA");
227 for (i=0; i<(sizeof(_ReportLUNdata_struct)+15)/16; i++){
228 pout("%03d-%03d: ", 16*i, 16*(i+1)-1);
229 for (j=0; j<15; j++)
230 pout("%02x ",*stuff++);
231 pout("%02x\n",*stuff++);
232 }
233 pout("===== [%s] DATA END (%u Bytes) =====\n\n", "LUN DATA", (unsigned)sizeof(_ReportLUNdata_struct));
234 }
235
236 if (target >= 0 && target < (int) be32toh(luns->LUNListLength) / 8)
237 {
238 memcpy(physlun, luns->LUN[target], 8);
239 free(luns);
240 return 0;
241 }
242
243 free(luns);
244 return 1;
245}
246#endif
int cciss_io_interface(int device, int target, struct scsi_cmnd_io *iop, int report)
#define CCISS_H_CVSID
Definition: cciss.h:14
#define CCISS_PASSTHRU
#define ATTR_SIMPLE
#define XFER_READ
#define CISS_MAX_LUN
#define TYPE_CMD
u32 size
Definition: megaraid.h:0
#define SEND_IOCTL_RESP_SENSE_LEN
Definition: os_linux.cpp:490
#define LSCSI_DRIVER_SENSE
Definition: os_linux.cpp:493
#define ENOTSUP
Definition: os_linux.cpp:88
void dStrHex(const uint8_t *up, int len, int no_ascii)
Definition: scsicmds.cpp:368
#define DXFER_NONE
Definition: scsicmds.h:108
#define DXFER_FROM_DEVICE
Definition: scsicmds.h:109
#define SCSI_STATUS_CHECK_CONDITION
Definition: scsicmds.h:320
void pout(const char *fmt,...)
Definition: smartd.cpp:1338
uint8_t * sensep
Definition: scsicmds.h:123
uint8_t * dxferp
Definition: scsicmds.h:121
int dxfer_dir
Definition: scsicmds.h:119
size_t cmnd_len
Definition: scsicmds.h:118
size_t resp_sense_len
Definition: scsicmds.h:127
size_t dxfer_len
Definition: scsicmds.h:122
size_t max_sense_len
Definition: scsicmds.h:125
uint8_t scsi_status
Definition: scsicmds.h:128
uint8_t * cmnd
Definition: scsicmds.h:117