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