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